前言
在自定义View中其实还有一个十分常见的类是我们经常会使用到的那就是LayoutInflater
。为什么会说它常用呢?还记得之前的文章有讲过,自定义View有一种实现方式是通过多个已有控件进行组合来实现的,那么这就需要通过LayoutInflater
的inflate
方法对定义好的xml文件进行转译,对,没错,是转译,前文中提到的这个方法其原理就是对xml文件进行读取,进而转化为实际的布局。
关于LayoutInflater
的inflate
方法其实用一直在用,也都知道它最终是用来获取View对象的,但是这个方法最让人搞不清楚的是它的参数,所以本文主要的内容是来讲解一下其参数的具体含义。
方法分析
一般的,我们是这样使用LayoutInflater
的inflate
方法的:
val view = LayoutInflater.from(context).inflate(R.layout.view_custom, this)
通过如上的方法,我们就可以获取到我们所需要布局的View对象,那么我们进入到这个方法中去:
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) {
final Resources res = getContext().getResources();
View view = tryInflatePrecompiled(resource, res, root, attachToRoot);
if (view != null) {
return view;
}
XmlResourceParser parser = res.getLayout(resource);
try {
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}
这个方法所做的是将xml资源文件转化为一个Xml的解析器进而去进行下一步操作,此外这里二参方法还有另外一个重载方法:
public View inflate(XmlPullParser parser, @Nullable ViewGroup root) {
return inflate(parser, root, root != null);
}
其指向的也是接下来这个三参方法,说明方法调用到最后都会来到下面这个方法来执行核心逻辑:
在分析前,我们要明确我们分析的目的是理解方法参数的含义,从方法的调用顺序来看,主要关注的是root
和attachToRoot
这两个参数。
// 省略了安全判断和部分无用代码
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
synchronized (mConstructorArgs) {
final Context inflaterContext = mContext;
final AttributeSet attrs = Xml.asAttributeSet(parser);
Context lastContext = (Context) mConstructorArgs[0];
mConstructorArgs[0] = inflaterContext;
View result = root;
try {
advanceToRootNode(parser);
final String name = parser.getName();
···
// 获取当前根视图
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
ViewGroup.LayoutParams params = null;
// root != null
if (root != null) {
// 如果attachToRoot为false的话只会对当前布局设置其父布局的相关属性配置,但并不会将View add到父布局上
params = root.generateLayoutParams(attrs);
if (!attachToRoot) {
temp.setLayoutParams(params);
}
}
// root != null 同时attachToRoot为true,会在应用布局配置的同时将View添加到父布局上去
if (root != null && attachToRoot) {
root.addView(temp, params);
}
// root == null 不做任何操作,直接返回了创建好的View
if (root == null || !attachToRoot) {
result = temp;
}
}
return result;
}
}
简单地对方法地调用做了分析,其中源码具体实现没有展开,只追了我们关注那部分逻辑,下面根据追源码地结果来进行一下总结:
- root为null时,attachToRoot值失去作用,会返回一个View对象,但是不会有任何的操作,也不会依附于某个ViewGroup进行展示
- root不为null,attachToRoot为true,会将View加载到指定的父布局上,即root上
- root不为null,attachToRoot为false,view最外层的layout相关属性会配置,但是view不会加载到任何布局上,只用手动add后layout相关属性才会生效
以上就是关于inflate这个方法相关的解惑,重点分析了不同参数所最终实现的效果是怎么样的,一般的情况直接使用二参方法去获取View对象就可以啦,其它的根据实际场景去针对性的选择使用。