Android下LayoutInflater的正确使用姿势
2016-11-17 本文已影响2166人
DevWang
生成LayoutInflater实例:
// 方法1
LayoutInflater mInflater = LayoutInflater.from(context);
// 方法2
LayoutInflater mInflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
最常用加载布局的方法:
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
...省略实现代码...
}
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
...省略实现代码...
}
直接放上结论并验证讲解:
阅读源代码可知:
- inflate(resource, null);
只创建view,view没有LayoutParams值,然后直接返回view.
xml布局中最外层的layout_width、layout_height将失效. - inflate(resource, null, true);
同1. - inflate(resource, null, false);
同1. - inflate(resource, root);
创建view,然后执行root.addView(view, params),最后返回root.
params为父布局根据xml布局中的宽和高得到相应的LayoutParams - inflate(resource, root, true);
同4. - inflate(resource, root, false);
创建view,然后执行view.setLayoutParams(params),然后返回view.
params为父布局根据xml布局中的宽和高得到相应的LayoutParams
总结如下:
- 如果root为null,attachToRoot将失去作用,设置任何值都没有意义,加载的布局文件最外层的所有layout属性会失效,由父布局来重新指定.
- 如果root不为null,attachToRoot不论是true或false,加载的布局文件最外层的所有layout属性都有效,唯一的不同是:
attachToRoot为true时,会自动调用root.addView(view, params),最后返回root;
attachToRoot为false时,会返回view,需手动调用root.addView(view, params). - 在不设置attachToRoot参数的情况下,如果root不为null,attachToRoot参数默认为true.
废话不多说,直接上代码,首先定义三个xml:
main.xml - 此布局为父布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#519C9A"
android:orientation="vertical" />
item1.xml - 此布局高度固定
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="100dp"
android:layout_height="50dp"
android:background="#C5C1AA"
android:gravity="center"
android:text="我是内容"
android:textStyle="bold" />
item2.xml - 此布局高度自适应
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#A4A4A4">
<TextView
android:layout_width="100dp"
android:layout_height="50dp"
android:background="#C9C9C9"
android:gravity="center"
android:text="我是内容"
android:textStyle="bold" />
</RelativeLayout>
1. 如果root为null,attachToRoot将失去作用,设置任何值都没有意义,加载的布局文件最外层的所有layout属性会失效,由父布局来重新指定.
content.addView(mInflater.inflate(R.layout.item1, null));
content.addView(mInflater.inflate(R.layout.item1, null, true));
content.addView(mInflater.inflate(R.layout.item1, null, false));
content.addView(mInflater.inflate(R.layout.item2, null));
content.addView(mInflater.inflate(R.layout.item2, null, true));
content.addView(mInflater.inflate(R.layout.item2, null, false));
小伙伴们看到这里是不是感觉晕晕的,明明item1.xml和item2.xml中根布局设置的宽度不是match_parent,结果却是充满屏幕宽?
在上面我们指出:这种方法的调用只是根据xml布局创建了view,view没有设置LayoutParams值,而是在父布局调用addView(...)方法时给定params,下面给出代码:
addView(...)方法是在ViewGroup.java中:
public void addView(View child, int index) {
if (child == null) {
throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
}
LayoutParams params = child.getLayoutParams();
if (params == null) {
params = generateDefaultLayoutParams();
if (params == null) {
throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");
}
}
addView(child, index, params);
}
因为我们这里父布局root是LinearLayout,所以params变量是由调用了LinearLayout.java中的generateDefaultLayoutParams()方法生成
protected LayoutParams generateDefaultLayoutParams() {
// 水平布局下 宽度高度自适应
if (mOrientation == HORIZONTAL) {
return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
// 竖直布局下 宽充满屏幕,高度自适应
} else if (mOrientation == VERTICAL) {
return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
}
return null;
}
看到这里有没有一种恍然大悟的感觉!
2. 如果root不为null,attachToRoot不论是true或false,加载的布局文件最外层的所有layout属性都有效,唯一的不同是:
attachToRoot为true时,会自动执行root.addView(view, params),最后返回root;
attachToRoot为false时,会返回view,需手动调用执行root.addView(view, params).
// 情景1 - attachToRoot为true
mInflater.inflate(R.layout.item1, content, true);
mInflater.inflate(R.layout.item2, content, true);
// 情景2 - attachToRoot为false
content.addView(mInflater.inflate(R.layout.item1, content, false));
content.addView(mInflater.inflate(R.layout.item2, content, false));
情景1和情景2任选一个运行得到的结果如下:
3. 在不设置attachToRoot参数的情况下,如果root不为null,attachToRoot参数默认为true.
直接上源码,一目了然:
public View inflate(XmlPullParser parser, @Nullable ViewGroup root) {
return inflate(parser, root, root != null);
}
至此,文章结束,希望此文能帮助到你,如果对此文有不同见解,欢迎直接评论!
参考文档:
关于LayoutInflater的错误用法
Android LayoutInflater原理分析,带你一步步深入了解View(一)
Android应用setContentView与LayoutInflater加载解析机制源码分析