Android中inflate参数的写法:
android中我们寻找控件的方式是类似Button bn=findViewById(R.id.mybutton),返回的是一个控件的obj,如果我们想要查找一个xml的View对象,则应该通过View buttonView = LayoutInflater.from(this).inflate(R.layout.button, null);然后View对象中如果有mybutton,我们应该是buttonView.findViewById(R.id.mybutton)去获取这个button控件的obj,所以说findViewById是相对于某一View的,那么inflate中的几个参数与View之间有什么关系呢?
先解释一下inflate的三个参数的意思:
参数一:layoutID 需要加载的xml中layout资源的ID
参数二:root 需要附加到resource资源文件的根控件,inflate()会返回一个View对象,如果第三个参数attachToRoot为true,就将这个root作为根对象返回,否则仅仅将这个root对象的LayoutParams属性附加到resource对象的根布局对象上,也就是布局文件resource的最外层的View上。如果root为null则会忽略view根对象的LayoutParams属性。
参数三:attachToRoot 是否将root附加到布局文件的根视图上
先看一下下面的代码:
public class MainActivity extends Activity { private int flag = 2; private Button button; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);// View buttonView = LayoutInflater.from(this).inflate(R.layout.button, null); //方式二,这个其实是方式一的内部真实实现方式 RelativeLayout mainLayout = (RelativeLayout) findViewById(R.id.mainLayout); LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); switch(flag) { case 1: //默认的layout_width=wrap_content layout_height=wrap_content //这个的设置是在mainLayout.addView(buttonView1);中做的调用函数是params = generateDefaultLayoutParams(); //返回值是Button控件 View buttonView1 = inflater.inflate(R.layout.button, null);//这个时候button的width和heigth改变是没有任何意义的,因为它们不属于任何的主layout System.out.println("buttonView1 parent = "+buttonView1.getParent());//null System.out.println("buttonView1 layoutparam="+buttonView1.getLayoutParams());//null mainLayout.addView(buttonView1); button = (Button)findViewById(R.id.mybutton);//① break; case 2: //返回值是Button控件 View buttonView2 = inflater.inflate(R.layout.button, mainLayout, false);//这就相当于buttonView依附于mainLayout存在,因此设置宽高是有效果的 System.out.println("buttonView2 parent = "+buttonView2.getParent());//null mainLayout.addView(buttonView2); button = (Button)findViewById(R.id.mybutton);//② break; case 3: //返回值是RelativeLayout控件,也就是说buttonView3在root不为null 且attachRoot=true的时候返回的是root View buttonView3 = inflater.inflate(R.layout.button, mainLayout, true);//同样的是有ViewGroup不为null ,因此我们设置的宽高任然有效 //mainLayout.addView(buttonView3);//当我们的inflate的第说那个参数为true的时候,说明我们的buttonView自动添加到了布局文件mainLayout中,因此这里就不能重复添加了 button = (Button)findViewById(R.id.mybutton);//③ break; default: break; } button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MainActivity.this, "这是一个独立的button", 0).show(); } }); }}
然后是activity_main.xml的code:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/mainLayout" android:layout_width="match_parent" android:layout_height="match_parent">RelativeLayout>
然后是button.xml的写法:
<?xml version="1.0" encoding="utf-8"?> <Button xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/mybutton" android:layout_width="300dp" android:layout_height="100dp" android:text="这是一个独立的button" >Button>
我们可以看到上面有inflate的三种写法:
第一种是View buttonView1 = inflater.inflate(R.layout.button, null); 这里只带有两个参数,实际上第三个参数默认值是true,只是当root为null的时候第三个参数没什么意义!首先看一下返回值,返回的是一个View,我们可以打印一下,得到这个buttonView1是一个android.widget.Button{532e207c VFED..C. ……I. 0,0-0,0 #7f080001 app:id/mybutton}对象,由于root=null因此说明我们的button控件并没有添加到root中去,因此buttonView1.getParent()和buttonView1.getLayoutParams()应该都是null,因为这两个函数都是相对于layout而言的,但是为什么我们看到显示结果里面会有button的大小了,而且貌似还是wrap_content属性的?
通过查看code我们发现了:
mainLayout.addView(buttonView1);//进入之后显示public void addView(View child) { addView(child, -1);}//然后是(这里我们发现当child.getLayoutParams为null的时候调用的是generateDefaultLayoutParams) public void addView(View child, int index) { LayoutParams params = child.getLayoutParams(); if (params == null) { params = generateDefaultLayoutParams(); if (params == null) { throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null"); } } addView(child, index, params); }//再次追进去发现,一个包裹属性呈现在面前了,这就是为什么我们button显示上面的模样,而且**更进一步的发现如果button自己设置宽高是没有任何用的,不会起作用**: protected LayoutParams generateDefaultLayoutParams() { return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); }
第二种写法:View buttonView2 = inflater.inflate(R.layout.button, mainLayout, false);
同样先看一下返回值,返回值同样的是Button,因为第三个参数没有关联root View,然后是看我们设置Button 的宽高之后有没有效果图片为:
这里我们可以看到我们设置的button的大小都正常的显示了但是有几个特点:
1.buttonView2.getParent()为null(没有关联root)
2.buttonView2.getLayoutParams());//android.widget.RelativeLayout$LayoutParams@532ed7b4明显看到不同于第一中写法的null,这里的LayoutParams是父控件类型,在源码中我们可以看到这样一段code:
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);** if (!attachToRoot) { // Set the layout params for temp if we are not // attaching. (If we are, we use addView, below) **temp.setLayoutParams(params);** }}
首先root生成了params,这也就是为什么我们获取的类型是root的类型,并且我们的attachToRoot=false,因此进入了第二句setLayoutParams,temp是我们inflate函数返回的值,也就是我们这里的button视图,因此我们的button怎么显示现在就看params是怎么来的:
params = root.generateLayoutParams(attrs);------->final AttributeSet attrs = Xml.asAttributeSet(parser);-------------> public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot)----------->XmlResourceParser parser = getContext().getResources().getLayout(resource);----->inflate(int resource, ViewGroup root, boolean attachToRoot)----> inflater.inflate(**R.layout.button**, mainLayout, false);
上面我们采用倒追的方式展现,我们首先是调用了inflate,传入一个layoutId,然后追进去发现我们的parser是通过拿资源得到的parse而资源就是R.layout.button,因此属性值的获取全部是以button的设置为参考,最后我们通过root生成了layoutParams属性值,这也就是为什么显示效果就是button设置的layout_width 和layout_height
3:由于我们第三个参数是false,因此我们的button的获取应该是在addView之后然后findViewById,不然会造成空指针异常(这个效果同写法一)我们可以通过buttonView2.findVIewById来获取,这样没啥问题
写法三的解析:View buttonView3 = inflater.inflate(R.layout.button, mainLayout, true);
1.先来看返回值,返回的居然是一个RelativeLayout的对象,也就是说返回的是mainLayout,这个不就是我们的root么,因此当root!=null的时候且attachToRoot=true的时候返回的是我们的root对象,而且同样我们的params能正确的显示,我们可以理解为关联了一个layout,因此button的layout属性有了关联的View,所以能正确的显示出来了(if(root!=null) params = root.generateLayoutParams(attrs);),
2.getParent() 返回的是android.widget.FrameLayout 而getLayoutParams返回的是android.widget.FrameLayout$LayoutParams,这是因为在setContentView()方法中,Android会自动在布局文件的最外层再嵌套一个FrameLayout,因此所有的控件父控件都是FrameLayout了,而现在的params也就通过FrameLayout来设置了
3.不知道有没有发现我们居然没有addView,结果button就显示在我们的界面上了,而且我们的③直接这样写居然也没有前面提到的空指针异常的问题(前面都要addView之后才能findViewById),这是为什么?
通过code我们可以发现:
// 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; }
当root != null && attachToRoot 的时候系统自动的为我们做了addView的动作,因此我们就没有必要再次addView,如果再次添加,系统也会提示我们已经添加过了,不要重复添加的错误,同样我们看到了root=null的时候直接的返回temp什么都没做,这也就再次说明为啥root=null的时候button的显示控件尺寸不生效
暂时总结到这里,说的不对写请大神拍砖,多谢!
更多相关文章
- Android2.3 x86 安装实战
- CoderPig’s Android(安卓)Study Note——目录
- Android带文字的ImageButton实现
- android自定义view控件
- 安卓学习笔记之使用widget桌面小控件及源码分析
- Android使用HttpPost向服务器发送Json数据
- android 环境配置和安装, Android系统包说明,基本控件,常用代码,
- Android(安卓)FrameLayout布局中的控件设置居中动态设置
- 背景选择器-selector