LayoutInflater解析:看了几篇博客巩固了自己的理解,说说自己对LayoutInflater浅显的理解:
常用读取xml,生成view的方法:
View view = View.inflate(context,resource,null);
进一步查看源码:其实调用的是LayoutInflater
public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) {
LayoutInflater factory = LayoutInflater.from(context); //这里需要一个上下文
return factory.inflate(resource, root);//调用的是LayoutInflater的inflate方法.
//也就是常用的LayoutInflater.from(context).inflate
//等于LayoutInflater.getService.inflate
}
再进一步查看
可以看出,LayoutInflater,其实是通过Context的getSystemService获取到的系统服务对象,
public static layoufrom(Context context) {
//context.getSystemService,这不是activity里获取系统服务类的方法么.
LayoutInflater LayoutInflater =(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (LayoutInflater == null) { //如果拿不到这个服务类就会抛出异常.
throw new AssertionError("LayoutInflater not found.");
}
return LayoutInflater;
}
总结:
//例1.生成view,但不指定父容器,如果父容器为null,那么设置ture还是false结果都一样
LayoutInflater.from(context).inflate(id,null);
//例2.结果和1一样,
LayoutInflater.from(context).inflate(id,null,false);
//例3.结果和1一样
LayoutInflater.from(context).inflate(id,null,true);
//例4.生成view,指定父容器,并添加到其中,获取parent的Layoutparmas设置view的Layoutparmas.
LayoutInflater.from(context).inflate(id,parent,true);
//例5.生成view,指定父容器,不添加到其中,获取parent的Layoutparmas设置view的Layoutparmas.
LayoutInflater.from(context).inflate(id,parent,false);
用例1,2,3生成的view是没有Layoutparmas的.所以必须手动设置,不然xml里面设置的属性会失效
用例4,5设生成的view,不管设置的true还是false,生成的view都会从parent中得到Layoutparmas,区别在于,是否添加到parent中
如果使用例4,则不要再去parent.addview(),否则会抛出异常
踩坑分析:
LinearLayout layout = (LinearLayout)findViewById(R.id.container);
View view = View.inflate(this, R.layout.layout_menu_item, null);
layout.addView(view);
这样写的话,你就会发现布局文件R.layout.layout_menu_item中的android:layout_width=”80dp”不起作用!!也就是说View.inflate方法忽略了布局文件的宽度设置
所以猜想是 第三个参数ViewGroup root
LinearLayout layout = (LinearLayout)findViewById(R.id.container);
View view = View.inflate(this, R.layout.layout_menu_item, layout);
layout.addView(view);
上面的崩溃
改为下面成功
LinearLayout layout = (LinearLayout)findViewById(R.id.container);
View view = View.inflate(this, R.layout.layout_menu_item, layout);
View.inflate方法自动将生成的View添加到了这个ViewGroup root中去了!!
其实View.inflate方法是调用了LayoutInflater.from(context).inflate(resource, root, root != null)方法,而inflate方法的三个参数如下:
* resource: 布局文件的id,比如R.layout.layout_menu_item
* root:这是一个可选参数,resource布局文件中layout_*参数设置的参照物就是这个root,也就是说inflate方法会根据这个root的大小,将resource布局文件中layout_*参数转换成一个LayoutParam对象
* attachToRoot:是否将这个生成的View添加到这个root中去
inflate方法会返回resource布局文件产生的View
上面栗子中调用了View.inflate(Context context, int resource, ViewGroup root),这个方法本质上是调用了了LayoutInflater.from(context).inflate(resource, root, root != null), 在这个inflate方法中可以找到下面代码:
// 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);
}
可见inflate方法自动将这个生成的View添加到了这个root中去了
踩坑总结:
1. 调用LayoutInflater.inflate方法,并且将root参数设置为null,就等于忽略了xml布局文件中的layout_×参数
2. 如果root不为null,并且attachRoot=true,那么就会根据root生成一个布局文件View的LayoutParam对象,并且将这个View添加到root中去,并且返回这个root的View
3.
因此,最好还是使用这个代码吧:View v1 = LayoutInflater.from(this).inflate(R.layout.layout_menu_item, layout, false);