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的显示控件尺寸不生效
暂时总结到这里,说的不对写请大神拍砖,多谢!

更多相关文章

  1. Android2.3 x86 安装实战
  2. CoderPig’s Android(安卓)Study Note——目录
  3. Android带文字的ImageButton实现
  4. android自定义view控件
  5. 安卓学习笔记之使用widget桌面小控件及源码分析
  6. Android使用HttpPost向服务器发送Json数据
  7. android 环境配置和安装, Android系统包说明,基本控件,常用代码,
  8. Android(安卓)FrameLayout布局中的控件设置居中动态设置
  9. 背景选择器-selector

随机推荐

  1. Android(安卓)OpenGL ES 基础篇
  2. Android重学之查漏补缺——Context引起的
  3. IPC多进程模式学习笔记
  4. Android多渠道Ant打包详细
  5. Android(安卓)Service分析
  6. Android位置服务--BaiduMap的使用(2)
  7. android 关系型数据库 SQLiteDatabase的
  8. Android(安卓)通过 Intent 传递类对象或l
  9. JetPack介绍
  10. Android之WebView安全