在android中我们经常会加载一个view布局,对于view的加载有两大方式,一种是在xml中写好布局文件,这个种方式简单方便使代码和UI界面隔离,耦合性比较低,但是他不够灵活,不能够动态的变化。还有一种是直接在代码里面写布局,他的可以实现布局的动态添加,但是缺点是使代码变得庞大臃肿,耦合性增强,一般情况下都是尽量在xml文件里面写,在代码里面动态控制,二者配合完成,在这里我讲总结四种xml文件加载的常用方法。
1、使用view的静态方法
View view=View.inflate(context, R.layout.child, null);
2、通过系统获取
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view= inflater.inflate(R.layout.child, null);
3、通过LayoutInflater
LayoutInflater.from(this).inflate(int resource, ViewGroup root);
LayoutInflater.from(this).inflate(int resource, ViewGroup root, boolean attachToRoot);
4、通过getLayoutInflater
getLayoutInflater().inflate(int resource, ViewGroup root);
getLayoutInflater().inflate(int resource, ViewGroup root, boolean attachToRoot);
view的inflate详解:
inflate函数其实就是封装了一个xml解析器而已,通过解析xml文件解析出节点的名字和属性.然后根据名字找到该View对应的类,调用该类的构造函数(当然还有把解析出来的属性传递给构造函数)生成该view.然后不断递归知道把所有节点解析完.(会根据层次结构生成一个view tree);
不管是调用哪个方法,最终调用的都是:
public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot)
- 参数一:指定资源的文件
- 参数二:给此生成的view指定一个父控件view,添加进去
- 参数三:是否添加
如果不添加的话有一下三种表示相同的意思:
LayoutInflater.from(this).inflate(R.layout.activity_main, null, true);
LayoutInflater.from(this).inflate(R.layout.activity_main, null, false);
LayoutInflater.from(this).inflate(R.layout.activity_main, viewGroup, false);
View.inflate(this, R.layout.activity_main,null);
如果添加的话只有下面一种:
LayoutInflater.from(this).inflate(R.layout.activity_main, viewGroup, true);
那么什么时候用那个呢?一般遵循如下原则:
(1)如果需要添加到指定的父布局:
- inflate(R.layout.activity_main, viewGroup, true);
(2)如果明确知道父布局不会添加:
- inflate(R.layout.activity_main, null);
- inflate(R.layout.activity_main, null, true);
- inflate(R.layout.activity_main, null, false);
- inflate(R.layout.activity_main, viewGroup, false);
(3)如果不清楚父布局是否会添加:
- inflate(R.layout.activity_main, viewGroup, false);
inflate加载布局宽高不足问题:
在一些Recycleview或者ListView中加载item布局的时候有时候会发现设置的的item宽度不能填充父布局或者高度失效了,这是因为inflate使用的方法不正确,在这些容器类的控件中父布局容器已经帮助我的写好添加布局的逻辑了,这是不需要我们在额外处理了,这时候我们只能使用:
inflate(R.layout.activity_main, viewGroup, false);
其他方式或多或少的会出现一些问题,例如背景颜色不能填充父布局,设置的height失效,变成了包裹内容,在这设置为true的情况下还有可能会抛出异常。下面从源码角度来看看宽高失效的原因,只看核心:
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);
}
}
如何,当传递过来的布尔值attachToRoot为false的时候会设置一个LayoutParams,这个LayoutParams参数就是item的xml中根布局配置的宽高信息。如果不设置,默认会为true,这段代码就不会被执行,导致宽高失效。所以一般情况下建议使用全参方法,一般不会出现什么问题:
inflate(int resource, ViewGroup root, boolean attachToRoot);