之前在动态加载一个布局时用
View.inflate()
去加载,最后没加载出来,换为LayoutInflater.from(mContext).inflate()
之后加载成功。具体场景我没记清了,但是我们可以通过了解这两个方式加载布局的方法来规避以后 使用可能出现的问题。
既然是由 LayoutInflater.from(mContext).inflate()
引出的问题那就从怎么使用开始去一步一步深挖。
LayoutInflater.from(this).inflate()
有 4 个构造方法,前面三个构造方法最终都会调用最后一个构造方法
inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot)
进行布局的解析。
它的四个构造方法如下:
第一个构造方法public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) { return inflate(resource, root, root != null); } 第二个构造方法public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) { // 真正实现的过程太长,这里就不贴代码了,可自行去查看源码} 第三个构造方法public View inflate(XmlPullParser parser, @Nullable ViewGroup root) { return inflate(parser, root, root != null); } 第四个构造方法public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) { // 真正实现的过程太长,这里就不贴代码了,可自行去查看源码}
我们常用的是第一个构造方法,但是第一个构造方法会调用第二个构造函数,所以我们 直接分析第二个构造方法。
它的构造方法参数介绍如下所示:
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) { }
参数解释:
@param resource
布局文件id
(例如R.layout.main_page
)@param root
如果参数三
attachToRoot
为true
, 则参数二是作为参数一中布局文件的父控件如果参数三
attachToRoot
为false
, 则参数二是作为提供一组LayoutParams
值的对象
@param attachToRoot
指定参数一的布局View
对象是否要作为 第二个参数控件上作为子控件
返回值:
@return
若root
不为空,且第attachToRoot
为true
,则返回root
作为根布局,否则,返回参数一view
对象的根布局 作为根布局
LayoutInflater.from(mContext).inflate() 小结
来源于文末 郭神 博客参考
如果
root
为null
,attachToRoot
将失去作用,设置任何值都没有意义,加载的布局文件最外层的所有layout
属性会失效,由父布局来重新指定.
实例验证
图一是root
为null
,attachToRoot=true
修改 R.layout.inflate_test_btn
的宽度为300dp
的结果,很明显没修改成功。在测试过程中我修改了 attachToRoot=false
,结果还是不变。
图一.png
图二是修改了父布局宽度为300dp
图二.png
验证结果正确:由父布局指定。
如果
root
不为null
,attachToRoot
不论是true
或false
,加载的布局文件最外层的所有layout
属性都有效,唯一的不同是:attachToRoot
为true
时,会自动调用root.addView(view, params)
,最后返回root
;
实例验证
resource
为R.layout.inflate_test_btn
,attachToRoot
为true
,root
为contentLayout
,完整调用如:LayoutInflater.from(this).inflate(R.layout.inflate_test_btn, contentLayout, true);
这时候如果不处理,会崩溃:
The specified child already has a parent. You must call removeView() on the child's parent first.
通过打印 parent 得到如下信息:
onCreate: parent---->android.widget.LinearLayout{4016a11 V.E...... ......I. 0,0-0,0 #7f0d007e app:id/root_layout}
原来还可以这样查看父布局。。
根据提示我们只能先移除其它子view
再添加
结合图三以及崩溃日志,可以证明会自动调用 root.addView(view, params)。
图三.jpg
验证结果正确:会自动调用 root.addView(view, params),最后返回 root。
attachToRoot
为false
时,会返回view
,需手动调用root.addView(view, params).
实例验证
resource
为R.layout.inflate_test_btn
,attachToRoot
为false
,root
为contentLayout
,完整调用如:LayoutInflater.from(this).inflate(R.layout.inflate_test_btn, contentLayout, false);
通过打印 parent 得到如下信息:
onCreate: parent---->null 不会崩溃,可以正常添加, 而且父布局中的子 view 都存在
图四可以证明 root.addView()
是需要手动添加的.
图四.png
验证结果:需手动调用 root.addView(view, params)
在不设置
attachToRoot
参数的情况下,如果root
不为null
,attachToRoot
参数默认为true
.
实例验证
resource
为R.layout.inflate_test_btn
,attachToRoot
不设置或者是设置为false
,root
为contentLayout
,完整调用如:LayoutInflater.from(this).inflate(R.layout.inflate_test_btn, contentLayout, false);
LayoutInflater.from(this).inflate(R.layout.inflate_test_btn, contentLayout,);
LayoutInflater.from(this).inflate(R.layout.inflate_test_btn,contentLayout); 会崩溃LayoutInflater.from(this).inflate(R.layout.inflate_test_btn,contentLayout,false); 不会崩溃
验证结果正确:如果 root 不为 null, attachToRoot 参数默认为 true.
关于 View 类的 inflate 方法
View.inflate
是对LayoutInflater inflate
的进一步封装,但是只实现了LayoutInflater inflate
两个参数的构造方法,所以功能相对LayoutInflater
会弱一些。我们可以通过源码直接看出二者的关系。
View.inflate
实现的源码如下:
参数介绍: context 表示上下文 resource 表示要填充的 `xml` 文件 root 填充成的 `view` 对象的根布局public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) { LayoutInflater factory = LayoutInflater.from(context); return factory.inflate(resource, root); } 构造方法中调用 LayoutInflater.from(this).inflate 两个参数 的 inflatepublic View inflate(@LayoutRes int resource, @Nullable ViewGroup root) { return inflate(resource, root, root != null); }
作者:_龙衣
链接:https://www.jianshu.com/p/407c3eae7eb8
共同学习,写下你的评论
评论加载中...
作者其他优质文章