https://blog.csdn.net/chenliguan/article/details/82314122?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.control&dist_request_id=&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.control
1 LayoutInflater用于加载布局
LayoutInflater用于加载布局的。加载布局的任务通常都是在Activity中调用setContentView()方法来完成的。其实setContentView()方法的内部也是使用LayoutInflater来加载布局的,只不过这部分源码是内部的。先看下LayoutInflater的基本用法,首先需要获取到LayoutInflater的实例,有两种方法可以获取到:
// 第一种写法如下:
LayoutInflater layoutInflater = LayoutInflater.from(context);
// 还有另外一种写法也可以完成同样的效果:
LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// 得到了LayoutInflater的实例之后就可以调用它的inflate()方法来加载布局了,如下所示:
layoutInflater.inflate(resourceId, root);
2 View.inflate和LayoutInflater.inflate效果的区别
(1)平时Recyclerview加载item中,adapter的getView方法中,我们经常用到LayoutInflater.inflate这样的方法来加载布局xml,平时一直就是这么用的,也没什么疑问。
LayoutInflater.from(mContext).inflate(R.layout.item_consume_recharge_record, parent, false);
1
(2)一次在加载布局时,使用了如下的方法View.inflate加载布局:
@Override
public ConsumeRechargeRecordViewHolder onCreateViewHolder_(ViewGroup parent, int viewType) {
View itemView = View.inflate(mContext, R.layout.item_consume_recharge_record, null);
return new ConsumeRechargeRecordViewHolder(itemView);
}
得到的效果如下,没有将item的布局文件最外层的所有layout属性设置:
(3)尝试多次调整后,使用LayoutInflater.inflate来加载布局,代码以及得到的效果截图如下,将item的布局文件最外层的所有layout属性设置(有边框):
@Override
public ConsumeRechargeRecordViewHolder onCreateViewHolder_(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(mContext).inflate(R.layout.item_consume_recharge_record, parent, false);
return new ConsumeRechargeRecordViewHolder(itemView);
}
3 原理分析
3.1 View.inflate与LayoutInflater.inflate的区别
虽然已经实现了效果,但心中的疑惑(为什么是这样的对比效果?)一直没解开,非常的难受,周末沉下心来研究一番,终于知道的原因所在,耶。
(1)首先看View.inflate的源码:
// View.inflate(context, resource, root)
public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) {
LayoutInflater factory = LayoutInflater.from(context);
return factory.inflate(resource, root); // 其实内部也是用LayoutInflater实现的:
}
(2)LayoutInflater.inflate的源码:
// LayoutInflater.inflate(resource, root)
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
return inflate(resource, root, root != null);
}
3.2 Inflate的三个参数(int resource, ViewGroup root, boolean attachToRoot)分析
(1)那对于Inflate的三个参数(int resource, ViewGroup root, boolean attachToRoot)是什么意思呢?
(2)先看源码:
public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
synchronized (mConstructorArgs) {
final AttributeSet attrs = Xml.asAttributeSet(parser);
mConstructorArgs[0] = mContext;
View result = root;
try {
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG &&
type != XmlPullParser.END_DOCUMENT) {
}
if (type != XmlPullParser.START_TAG) {
throw new InflateException(parser.getPositionDescription()
+ ": No start tag found!");
}
final String name = parser.getName();
if (TAG_MERGE.equals(name)) {
if (root == null || !attachToRoot) {
throw new InflateException("merge can be used only with a valid "
+ "ViewGroup root and attachToRoot=true");
}
rInflate(parser, root, attrs);
} else {
View temp = createViewFromTag(name, attrs);
ViewGroup.LayoutParams params = null;
if (root != null) {
params = root.generateLayoutParams(attrs);
if (!attachToRoot) {
temp.setLayoutParams(params);
}
}
rInflate(parser, temp, attrs);
if (root != null && attachToRoot) {
root.addView(temp, params);
}
if (root == null || !attachToRoot) {
result = temp;
}
}
} catch (XmlPullParserException e) {
InflateException ex = new InflateException(e.getMessage());
ex.initCause(e);
throw ex;
} catch (IOException e) {
InflateException ex = new InflateException(
parser.getPositionDescription()
+ ": " + e.getMessage());
ex.initCause(e);
throw ex;
}
return result;
}
}
(3)核心部分源码如下,具体分析源码的逻辑:
View temp = createViewFromTag(name, attrs);
// 布局文件最外层的layout属性
ViewGroup.LayoutParams params = null;
if (root != null) {
params = root.generateLayoutParams(attrs);
// 3.root不为null,attachToRoot设为false,则会将布局文件最外层的所有layout属性进行设置
if (!attachToRoot) {
temp.setLayoutParams(params);
}
}
rInflate(parser, temp, attrs);
// 2.root不为null,attachToRoot设为true,则会给布局文件指定一个父布局,即root
if (root != null && attachToRoot) {
root.addView(temp, params);
}
// 1.root为null,attachToRoot将失去作用,则布局文件设置任何值都没有意义,仅仅是解析布局文件的子View
if (root == null || !attachToRoot) {
result = temp;
}
(4)结论:
1. 如果root为null,attachToRoot将失去作用,则布局文件最外层设置任何值都没有意义,仅仅是解析布局文件的子View。
2. 如果root不为null,attachToRoot设为true,则会给布局文件指定一个父布局,即root。(merge作为父布局标签为什么需要attachToRoot设为true的原因)
3. 如果root不为null,attachToRoot设为false,则会将布局文件最外层的所有layout属性进行设置,当该view被添加到父view当中时,这些layout属性会自动生效。
4. 在不设置attachToRoot参数的情况下,如果root不为null,attachToRoot参数默认为true;如果root为null,attachToRoot参数为false。
4 为什么有区别?
(1)所以,当使用View.inflate(mContext, xml, null)时,传入的root为null,attachToRoot为false,attachToRoot将失去作用,则布局文件最外层设置任何值都没有意义,仅仅是解析布局文件的子View,所以得到的效果仅仅是item内部子View。
(2)那又有疑问了,设置View.inflate(mContext, xml, parent)不就可以了吗?结果是程序崩溃,为什么?
(3)因为Recyclerview中adapter的getView方法加载的布局已经设置了父布局,不需要指定一个父布局——第2点,只需要将布局文件最外层的所有layout属性进行设置——第3点,所以使用如下的方法加载生效:
View itemView = LayoutInflater.from(mContext).inflate(R.layout.item_consume_recharge_record, parent, false);
1
5 学习链接
Android LayoutInflater原理分析,带你一步步深入了解View(一)
View.inflate和LayoutInflater的inflate方法区别
View.inflate()和LayoutInflater.inflate()的区别
编码之路
5536
一、LayoutInflater.inflate() 该方法适用于所有布局填充的的场景,但使用前需要先实例化LayoutInflater对象 1. 获取LayoutInflater实例 getLayoutInflater(); 这个方法可以在Activity和Fragment中使用,不过在Fragment中使用时,要传入一个bundle参数 // Activity中使用 LayoutInflater layoutInflater = getLayoutInflater(); // Fragment中使用
Android高手进阶教程(五)之----Android 中LayoutInflater的使用!
Android_Tutor的专栏
2万+
大家好我们这一节讲的是LayoutInflater的使用,在实际开发种LayoutInflater这个类还是非常有用的,它的作用类似于findViewById(), 不同点是LayoutInflater是用来找layout下xml布局文件,
————————————————
版权声明:本文为CSDN博主「小冠^-^」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/chenliguan/article/details/82314122