您的位置:首页 > 移动开发 > Android开发

Android LayoutInflater动态添加子View的属性生效问题

2015-10-23 14:27 344 查看
  


  最近正在做动态添加Button的效果。结果动态添加的按钮的样式设置过了但是margin属性却总是被忽略,不起作用。这个还是得从LayoutInflater的使用开始说起。

  LayoutInflater有三种加载方式,之前看过网上的很多关于LayoutInflater的获取方式,但是想要使动态加载的view的属性生效,实际上取决于我们使用的LayoutInflater的方法。(不要感觉下面的LayoutInflater 的获得方式没用,重点是第二部分动态加载view的方式)

获得 LayoutInflater 的三种方式

这里简单介绍一下LayoutInflater 获得的三种方式,如果你已经很清楚了就不需要看了

方式一:

//调用Activity的getLayoutInflater()
LayoutInflater inflater = getLayoutInflater();


方式二:

LayoutInflater inflater = LayoutInflater.from(context);


方式三:

LayoutInflater inflater =  (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);


动态加载方式

这部分才是重点

既然要动态加载那就需要获得我们的view,view的获得方式,根据方法的重载,传递的参数不同,调用的方法也不同。下面是LayoutInflater的源码,结合源码来看一下。

LayoutInflater获得View有三种方法,主要使用的下面两中方式:

代码实例:

这种调用方式会忽略View的属性

mView=inflater.inflate(R.layout.activity_travel_starttravel,null);


这种方式才是我们所想要的,不会使属性失效的方式

mView=inflater.inflate(R.layout.activity_travel_starttravel,mLinearLayoutEndTravel,false)


下面看下源码中他们的区别

方式一:

/**
* Inflate a new view hierarchy from the specified xml resource. Throws
* {@link InflateException} if there is an error.
*
* @param resource ID for an XML layout resource to load (e.g.,
*        <code>R.layout.main_page</code>)
* @param root Optional view to be the parent of the generated hierarchy.
* @return The root View of the inflated hierarchy. If root was supplied,
*         this is the root View; otherwise it is the root of the inflated
*         XML file.
*/
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
return inflate(resource, root, root != null);
}


注意:可以看出来方式一调用的是方式二的三个参数的传递方法,这就是关键了,因此我们直接来看方式二

方式二:

/**
* Inflate a new view hierarchy from the specified xml resource. Throws
* {@link InflateException} if there is an error.
*
* @param resource ID for an XML layout resource to load (e.g.,
*        <code>R.layout.main_page</code>)
* @param root Optional view to be the parent of the generated hierarchy (if
*        <em>attachToRoot</em> is true), or else simply an object that
*        provides a set of LayoutParams values for root of the returned
*        hierarchy (if <em>attachToRoot</em> is false.)
* @param attachToRoot Whether the inflated hierarchy should be attached to
*        the root parameter? If false, root is only used to create the
*        correct subclass of LayoutParams for the root view in the XML.
* @return The root View of the inflated hierarchy. If root was supplied and
*         attachToRoot is true, this is root; otherwise it is the root of
*         the inflated XML file.
*/
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
final Resources res = getContext().getResources();
if (DEBUG) {
Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
+ Integer.toHexString(resource) + ")");
}

final XmlResourceParser parser = res.getLayout(resource);
try {
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}


方式二中再次进行了调用了方法inflate,也就是下面的方法

public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
synchronized (mConstructorArgs) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");

final Context inflaterContext = mContext;
final AttributeSet attrs = Xml.asAttributeSet(parser);
Context lastContext = (Context) mConstructorArgs[0];
mConstructorArgs[0] = inflaterContext;
View result = root;

try {
// Look for the root node.
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG &&
type != XmlPullParser.END_DOCUMENT) {
// Empty
}
//有关XmlPullParser的部分先不管
if (type != XmlPullParser.START_TAG) {
throw new InflateException(parser.getPositionDescription()
+ ": No start tag found!");
}

final String name = parser.getName();

if (DEBUG) {
System.out.println("**************************");
System.out.println("Creating root view: "
+ name);
System.out.println("**************************");
}

if (TAG_MERGE.equals(name)) {
if (root == null || !attachToRoot) {
throw new InflateException("<merge /> can be used only with a valid "
+ "ViewGroup root and attachToRoot=true");
}

rInflate(parser, root, inflaterContext, attrs, false);
} else {
// Temp is the root view that was found in the xml
final View temp = createViewFromTag(root, name, inflaterContext, attrs);

ViewGroup.LayoutParams params = null;
//直接看这一部分,如果传入了view所要添加到的布局则会产生布局属性
if (root != null) {
if (DEBUG) {
System.out.println("Creating params from root: " +
root);
}
// Create layout params that match root, if supplied
//产生与布局相关的参数
params = root.generateLayoutParams(attrs);
//如果将attachToRoot设置为false则进行设置属性,否则不设置
//前面方式一与方式二默认传入的是root!=null,也就是传入了attachToRoot=true,因此不会设置属性了
if (!attachToRoot) {
// Set the layout params for temp if we are not
// attaching. (If we are, we use addView, below)
temp.setLayoutParams(params);
}
}

if (DEBUG) {
System.out.println("-----> start inflating children");
}

// Inflate all children under temp against its context.
rInflateChildren(parser, temp, attrs, true);

if (DEBUG) {
System.out.println("-----> done inflating children");
}

// We are supposed to attach all the views we found (int temp)
// to root. Do that now.
if (root != null && attachToRoot) {
root.addView(temp, params);
}

// Decide whether to return the root that was passed in or the
// top view found in xml.
if (root == null || !attachToRoot) {
result = temp;
}
}

} catch (XmlPullParserException e) {
InflateException ex = new InflateException(e.getMessage());
ex.initCause(e);
throw ex;
} catch (Exception e) {
InflateException ex = new InflateException(
parser.getPositionDescription()
+ ": " + e.getMessage());
ex.initCause(e);
throw ex;
} finally {
// Don't retain static reference on context.
mConstructorArgs[0] = lastContext;
mConstructorArgs[1] = null;
}

Trace.traceEnd(Trace.TRACE_TAG_VIEW);

return result;
}
}


重点理解部分:



因此,如果想要使你动态添加的按钮有效则必须使用方式二来添加按钮。下面附一个使用实例,实现的效果是博客开篇图片展示的效果。

使用实例

界面布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/activity_chart_subscribe_header"></include>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/light_grey"></View>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"

android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="已添加"
android:textSize="18sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="(点击删除)"
android:textSize="14sp"/>

</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/light_grey"></View>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="10dp"
>
<Button
android:id="@+id/button_nullsubscribe"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="20dp"
android:drawableTop="@mipmap/formdate_null_icon"
android:textColor="@color/grey"
android:visibility="gone"
android:background="@null"/>
<GridLayout
android:id="@+id/gridlayoyt_blank_chartsubscribe"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginTop="10dp"
android:columnCount="3"
android:rowCount="3"
android:minHeight="10dp"
android:minWidth="10dp"

android:layout_marginLeft="10dp"
>
<Button
android:id="@+id/button_gridlayout_blank_locate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="随时定位"
style="@style/SubscribeBlankButtonStyle"
/>

<Button
android:id="@+id/button_gridlayout_blank_cusvisit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="客户拜访"
style="@style/SubscribeBlankButtonStyle"
/>
<Button
android:id="@+id/button_gridlayout_blank_addnewcus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="新增客户"
style="@style/SubscribeBlankButtonStyle"
/>

<Button
android:id="@+id/button_gridlayout_blank_cusall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/SubscribeBlankButtonStyle"
android:text="客户总量"/>
</GridLayout>
</FrameLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/light_grey"></View>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="可添加"
android:layout_marginLeft="15dp"
android:layout_marginTop="10dp"
android:paddingBottom="10dp"
android:paddingTop="10dp"
/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/light_grey"></View>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<GridLayout
android:id="@+id/gridlayoyt_canadd_chartsubscribe"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:rowCount="2"
android:columnCount="3"
android:minHeight="10dp"
android:minWidth="10dp"
android:layout_marginLeft="10dp"
>
</GridLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/light_grey"></View>
</LinearLayout>




按钮的两种样式设置

<style name="SubscribeBlankButtonStyle">
<item name="android:textColor">@color/red</item>
<item name="android:background">@drawable/subscribe_button_red</item>
<item name="android:textSize">14sp</item>
<item name="android:layout_weight">1</item>
<item name="android:layout_columnWeight">1</item>
<item name="android:layout_marginTop">10dp</item>
<item name="android:layout_marginLeft">10dp</item>
<item name="android:layout_gravity">fill_horizontal</item>
</style>
<style name="SubscribeAddButtonStyle">
<item name="android:textColor">@color/deep_grey</item>
<item name="android:textSize">14sp</item>
<item name="android:maxWidth">80dp</item>
<item name="android:layout_weight">1</item>
<item name="android:layout_marginTop">10dp</item>
<item name="android:layout_columnWeight">1</item>
<item name="android:layout_marginLeft">10dp</item>
<item name="android:background">@drawable/subscribe_button_grey</item>
<item name="android:layout_gravity">fill_horizontal</item>
</style>


Button按钮的两个子View,编写在了xml文件中

红色按钮样式

<?xml version="1.0" encoding="utf-8"?>
<Button xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/SubscribeAddButtonStyle"

/>


灰色按钮

<?xml version="1.0" encoding="utf-8"?>
<Button xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/SubscribeBlankButtonStyle"

/>


MainActivity中的调用

public class ActivityChartSubscribe extends BaseActivity implements View.OnClickListener{
//返回报表界面的按钮注释
private Button mButtonBackToChart;
//已添加下面没有任何东西时的button
private Button mButtonBlank;

//已添加下面的GridLayout
private GridLayout mGridLayoutBlank;

//可添加下面的GridLayout
private GridLayout mGridLayoutAdd;

//已添加下面的按钮
private Button mButtonGridBlankLocate;
private Button mButtonGridBlankCusVisit;
private Button mButtonGridBlankAddNewCus;
private Button mButtonGridBlankCusAll;

private int TYPE_LOCATE=0x11;
private int TYPE_CUSVISIT=0x22;
private int TYPE_CusALL=0x33;
private int TYPE_AddNewCus=0x44;

private int mButtonCount=4;

private List<String> mButtonType;
private List<String> mButtonTypeAdd;

private SharedPreferences mSharedPreferences;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chart_subscribe);
chartsubscribefindview();
}

@Override
public void onClick(View view) {
switch ( view.getId()){
case R.id.button_backtochart_chartsubscribe:
//返回报表界面
SharedPreferences.Editor mEdit1= mSharedPreferences.edit();
mEdit1.putInt("Button_type", mButtonType.size()); /*sKey is an array*/

for(int i=0;i<mButtonType.size();i++) {
mEdit1.remove("Button_" + i);
mEdit1.putString("Button_" + i, mButtonType.get(i));
}
mEdit1.commit();
finish();
break;
case R.id.button_gridlayout_blank_locate:
deletebuttonfromgridblank(view, TYPE_LOCATE);
break;
case R.id.button_gridlayout_blank_cusvisit:
deletebuttonfromgridblank(view ,TYPE_CUSVISIT);
break;

case R.id.button_gridlayout_blank_cusall:
deletebuttonfromgridblank(view, TYPE_CusALL);
break;
case R.id.button_gridlayout_blank_addnewcus:
//从BlankGridlayout部分删除,新增客户
deletebuttonfromgridblank(view, TYPE_AddNewCus);

break;
}
}

/**
*该方法用于删除红色的按钮同时添加灰色的按钮
* @param v
*/
private void deletebuttonfromgridblank(View v,final int type) {
mGridLayoutBlank.removeView(v);
Button button=(Button)v;
mButtonCount--;

isnull();
LayoutInflater inflater=LayoutInflater.from(this);
//使用三个参数的方式加载Button
Button buttongridaddlocate=(Button)inflater.inflate(R.layout.button_subscribe_grey, mGridLayoutAdd,false);
for (int i=mButtonType.size()-1;i>=0;i--){
if (mButtonType.get(i).equals(button.getText().toString()))
{
mButtonType.remove(i);
}
}
for (int i=mButtonTypeAdd.size()-1;i>=0;i--){
if (mButtonTypeAdd.get(i).equals(button.getText().toString()))
{
mButtonTypeAdd.add(button.getText().toString());
}
}
if(type==TYPE_LOCATE){
buttongridaddlocate.setText("随时定位");

}
if (type==TYPE_CUSVISIT){
buttongridaddlocate.setText("客户拜访");

}
if (type==TYPE_CusALL){
buttongridaddlocate.setText("客户总量");
}
if (type==TYPE_AddNewCus){
buttongridaddlocate.setText("新增客户");
}
mGridLayoutAdd.addView(buttongridaddlocate);
buttongridaddlocate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View  view) {

addbuttontogridblank(view, type);
}
});

}
/**
* 该方法用于删除灰色的按钮同时添加红色的按钮
* @param v 要删除的灰色按钮
*/
private void addbuttontogridblank(View v,final int type) {
mGridLayoutAdd.removeView(v);
Button button= (Button) v;
mButtonCount++;
isnull();
LayoutInflater inflater=LayoutInflater.from(this);
Button buttongridblanklocate=(Button)inflater.inflate(R.layout.button_subscribe_red,mGridLayoutBlank,false);
for (int i=mButtonType.size()-1;i>=0;i--){
if (mButtonType.get(i).equals(button.getText().toString()))
{
mButtonType.add(button.getText().toString());
}
}

for (int i=mButtonTypeAdd.size()-1;i>=0;i--){
if (mButtonTypeAdd.get(i).equals(button.getText().toString()))
{
mButtonTypeAdd.remove(button.getText().toString());
}
}
if(type==TYPE_LOCATE){
buttongridblanklocate.setText("随时定位");

}
if (type==TYPE_CUSVISIT){
buttongridblanklocate.setText("客户拜访");

}
if (type==TYPE_CusALL){
buttongridblanklocate.setText("客户总量");

}
if (type==TYPE_AddNewCus){
buttongridblanklocate.setText("新增客户");

}
mGridLayoutBlank.addView(buttongridblanklocate);
buttongridblanklocate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
deletebuttonfromgridblank(view, type);
}
});
}
private void  chartsubscribefindview(){
//返回按钮
mButtonBackToChart= (Button) findViewById(R.id.button_backtochart_chartsubscribe);
//已添加部分没有任何信息时需要显示的按钮
mButtonBlank= (Button) findViewById(R.id.button_nullsubscribe);
mButtonBackToChart.setOnClickListener(this);
mButtonBlank.setOnClickListener(this);

//已添加的布局
mGridLayoutBlank= (GridLayout) findViewById(R.id.gridlayoyt_blank_chartsubscribe);
//可添加的布局
mGridLayoutAdd= (GridLayout) findViewById(R.id.gridlayoyt_canadd_chartsubscribe);

mButtonGridBlankLocate= (Button) findViewById(R.id.button_gridlayout_blank_locate);
mButtonGridBlankCusVisit= (Button) findViewById(R.id.button_gridlayout_blank_cusvisit);
mButtonGridBlankAddNewCus= (Button) findViewById(R.id.button_gridlayout_blank_addnewcus);
mButtonGridBlankCusAll= (Button) findViewById(R.id.button_gridlayout_blank_cusall);

mButtonGridBlankCusAll.setOnClickListener(this);
mButtonGridBlankLocate.setOnClickListener(this);
mButtonGridBlankCusVisit.setOnClickListener(this);
mButtonGridBlankAddNewCus.setOnClickListener(this);
mButtonType=new ArrayList<>();
mButtonTypeAdd=new ArrayList<>();
mSharedPreferences= getSharedPreferences("buttontype",MODE_PRIVATE);

}

private void isnull(){
if(mButtonCount==0){
mButtonBlank.setVisibility(View.VISIBLE);
}else{
mButtonBlank.setVisibility(View.GONE);
}
}

@Override
protected void onResume() {
int size = mSharedPreferences.getInt("Button_type", 0);
for(int i=0;i<size;i++) {
mButtonType.add(mSharedPreferences.getString("Button_" + i, null));
}
List<String> mButtonTypeAddCopy=mButtonTypeAdd;
for (int i=mButtonTypeAddCopy.size()-1;i>=0;i++){
switch (mButtonTypeAddCopy.get(i)){
case "随时定位":deletebuttonfromgridblank(mButtonGridBlankLocate, TYPE_LOCATE);
break;
case "客户拜访":deletebuttonfromgridblank(mButtonGridBlankCusVisit, TYPE_CUSVISIT);break;
case "新增客户":deletebuttonfromgridblank(mButtonGridBlankAddNewCus, TYPE_AddNewCus);break;
case "客户总量":deletebuttonfromgridblank(mButtonGridBlankCusAll, TYPE_CusALL);break;
}
}

super.onResume();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: