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(); } }
相关文章推荐
- Android开源框架Universal-Image-Loader详解
- Android缓存之磁盘缓存.对DiskLruCache进行封装便于存取.
- Android Studio 40个快捷键
- android 里listview和ScrollView的冲突问题
- android 获取控件高度
- Android项目:简易版QQ的实现
- Android实现输入手机号时自动添加空格
- 用travis-ci编译android版nodejs
- android导航栏隐藏与浮现
- Android使用BitmapRegionDecoder加载超大图片方案
- Android各种轮子
- Eclipse Android 代码自动提示消失解决办法Java xml
- System Permissions
- Android中CountDownTimer倒计时器用法实例
- Android自定义控件及自定义属性
- Android自定义控件及自定义属性
- Android Developper 学习
- 解决Android Studio/Idea在EI Captian下字体显示不正常的问题
- 如何区别Android手机卡三大运营商
- Android仿ios录音动画