Android LayoutInflater
请先阅读:
Android 源码分析 – LayoutInflater创建View的流程分析
除此之外,需要补充的内容:
inflate 方法返回值和 LayoutParams 参数生成
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
final Context inflaterContext = mContext;
final AttributeSet attrs = Xml.asAttributeSet(parser);
Context lastContext = (Context) mConstructorArgs[0];
mConstructorArgs[0] = inflaterContext;
// 返回值,默认为 root
View result = root;
// ...
// xml 生成的 view
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
ViewGroup.LayoutParams params = null;
if (root != null) {
// 生成 View 的 LayoutParams,前提是传入的root不为null
params = root.generateLayoutParams(attrs);
// 如果attachToRoot为 false,设置 LayoutParams
// 如果attachToRoot为 true,这里没有必要设置,因为后面会 addView
if (!attachToRoot) {
temp.setLayoutParams(params);
}
}
rInflateChildren(parser, temp, attrs, true);
// 如果 attachToRoot,直接将 view 添加到 root
if (root != null && attachToRoot) {
root.addView(temp, params);
}else {
// 这里做了改写,源代码为 if (root == null || !attachToRoot),其实是一个意思
// 返回值是生成的 view
result = temp;
}
return result;
}
结论:
-
root 参数不为 null,将被用来生成 view 的 LayoutParams 参数(调用 root.generateLayoutParams方法);
如果 root 参数为 null,生成的 view 没有 LayoutParams 参数,需要返回后自己设置;
-
如果root参数不为 null,attachToRoot 为 true 时,返回 root;attachToRoot 为 false 时,返回生成的 view,这时该 view 并未添加到 root 中,需要手动添加;
-
如果 root 参数为 null,attachToRoot 为 true 和 false 情况下,请自行分析,没有见到有人这么用过(这么使用没有意义),应该也不是api设计者的初衷;
LayoutInflater 的实现类 及 xml 文件中未指定全类名的 View 如果找到构造方法
其实,不过通过什么方式,得到的构造方法均为PhoneLayoutInflater对象,该类代码如下:
package com.android.internal.policy;
public class PhoneLayoutInflater extends LayoutInflater {
// 没有全类名(没有 "." 的类名),将尝试添加这些前缀,其实还有另一个前缀
// "android.view."
private static final String[] sClassPrefixList = {
"android.widget.",
"android.webkit.",
"android.app."
};
@Override protected View onCreateView(String name, AttributeSet attrs) throws ClassNotFoundException {
for (String prefix : sClassPrefixList) {
try {
View view = createView(name, prefix, attrs);
if (view != null) {
return view;
}
} catch (ClassNotFoundException e) {
// In this case we want to let the base class take a crack
// at it.
}
}
// 这里调用了 父类的 onCreateView方法,其中只有一行代码(return createView(name, "android.view.", attrs);)
return super.onCreateView(name, attrs);
}
}