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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值