LayoutInflater
程序员文章站
2024-02-11 00:02:46
...
LayoutInflater
获取 LayoutInflater
获得 LayoutInflater 共有以下三种方法,后两种方法实际上也是通过调用 Context 的 getSystemService
方法获取 PhoneLayoutInflater
实现类的实例。
// getSystemService
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// static LayoutInflater from(Context context)
LayoutInflater inflater = LayoutInflater.from(context);
// 在 Activity 内部调用 getLayoutInflater()
LayoutInflater inflater = getLayoutInflater();
inflate() 方法
在调用不同的四种 inflate
方法后,前三者最终调用了 inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot)
方法,其中 XmlPullParser
是 用于解析 XML 文件的 PULL 解析器对象。
- inflate(int resource, ViewGroup root)
- inflate(XmlPullParser parser, ViewGroup root)
- inflate(int resource , ViewGroup root, boolean attachToRoot)
- inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot)
// root 不为空的时候,attachToRoot 值默认为 true
public View inflate(int resource, ViewGroup root) {
// root不为空时,attachToRoot默认为true
return inflate(resource, root, root != null);
}
public View inflate(int resource, ViewGroup root, boolean attachToRoot) {
XmlResourceParser parser = getContext().getResources().getLayout(resource);
try {
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}
public View inflate(XmlPullParser parser, ViewGroup root) {
// root不为空时,attachToRoot默认为true
return inflate(parser, root, root != null);
}
public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
...
}
inflate() 的关键源码
public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
synchronized (mConstructorArgs) {
final AttributeSet attrs = Xml.asAttributeSet(parser);
// 首先注意result初值为root
View result = root;
try {
// 尝试找到布局文件的根节点
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG &&
type != XmlPullParser.END_DOCUMENT) {
// Empty
}
...
// 获取当前节点名称,如merge,RelativeLayout等
final String name = parser.getName();
...
// 处理merge节点
if (TAG_MERGE.equals(name)) {
// merge必须依附在一个根View上
if (root == null || !attachToRoot) {
throw new InflateException("<merge /> can be used only with a valid "
+ "ViewGroup root and attachToRoot=true");
}
rInflate(parser, root, attrs, false);
} else {
View temp;
// 根据当前信息生成一个View
temp = createViewFromTag(root, name, attrs);
...
ViewGroup.LayoutParams params = null;
if (root != null) {
// 如果指定了root参数的话,根据节点的布局参数生成合适的LayoutParams
params = root.generateLayoutParams(attrs);
// 若指定了attachToRoot为false,会将生成的布局参数应用于上一步生成的View
if (!attachToRoot) {
temp.setLayoutParams(params);
}
}
// 由上至下,递归加载xml内View,并添加到temp里
rInflate(parser, temp, attrs, true);
// 如果root不为空且指定了attachToRoot为true时,会将temp作为子View添加到root中
if (root != null && attachToRoot) {
root.addView(temp, params);
}
// 如果指定的root为空,或者attachToRoot为false的时候,返回的是加载出来的View,
// 否则返回root
if (root == null || !attachToRoot) {
result = temp;
}
}
} ... // 异常处理
return result;
}
}
根据源码可以得到:
- root != null & attachToRoot == true
把 resource 关联的布局加载为一个 View 作为 root 的子 View,然后返回 root。
并且resource 关联的布局 android:layout_xxx 布局参数有效。 - root != null & attachToRoot == false
把 resource 关联的布局加载为一个 View 直接返回。
并把 resource 关联的布局的 android:layout_xxx 布局参数作为 LayoutParams 保留。 - root == null
把 resource 关联的布局加载为一个 View 直接返回。
resource 关联的布局 android:layout_xxx 布局参数无效。
转载于:https://www.jianshu.com/p/2c59fb2d756b