本篇你将了解到:
-
LayoutInflater
获取方式 - 使用
LayoutInflater
如何获取到 View 对象
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(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
根据布局文件生成 View
我们根据源码来了解 LayoutInflater
是如何生成一个 View
对象的:
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);
if (!attachToRoot) {
// 若指定了attachToRoot为false,会将生成的布局参数应用于生成的 View
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;
}
}
根据源码可以将 inflate()
方法分为以下三种情况:
-
root != null & attachToRoot == true
- 把
resource
关联的布局加载为root
的子View
,然后返回root
。并且resource
关联的布局的参数在root
中生效。
- 把
-
root != null & attachToRoot == false
- 把
resource
关联的布局加载为一个View
直接返回。并把resource
关联的布局的参数作为LayoutParams
保留。
- 把
-
root == null
- 把
resource
关联的布局加载为一个View
直接返回。resource
关联的布局参数无效。
- 把
网友评论