文章目录
LayoutInflater分析
获取LayoutInflater对象
LayoutInflater layoutInflater = LayoutInflater.from(context);
LayoutInflater layoutInflater = activity.getLayoutInflater();
//本质都是调用第三种方式
LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflate方法参数说明
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot)
resource | root | attachToRoot | 说明 |
---|---|---|---|
XML布局 | root == null | 失去作用 | 由于子View的宽高属性是相对于父View的,没有指定父View,所以导致他的宽高属性失效。 |
XML布局 | root != null | attachToRoot == true | 会将子View添加到父View中 |
XML布局 | root != null | attacthToRoot == false | 会将子View外层的layout属性进行设置,子View被添加到父View中时,这些layout属性会自动生效。 |
源码分析
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
final Resources res = getContext().getResources();
//1.使用反射尝试获取提前编译好的View对象
//2.如果获取到View对象,则直接返回;如果没有获取到,则通过XML资源解析器
View view = tryInflatePrecompiled(resource, res, root, attachToRoot);
if (view != null) {
return view;
}
//根据资源id获取XML布局解析器
XmlResourceParser parser = res.getLayout(resource);
try {
//使用XML解析器对XML布局进行解析
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}
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();
//如果布局根标签为merge,则root不能为null,attachToRoot不能为false,否则抛出异常
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");
}
//解析XML布局
rInflate(parser, root, inflaterContext, attrs, false);
} else {
//根据XML解析获取根View对象
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
ViewGroup.LayoutParams params = null;
//如果root不为null
if (root != null) {
//获取root的布局参数
params = root.generateLayoutParams(attrs);
if (!attachToRoot) {
//如果attachToRoot==false,则View设置布局参数
temp.setLayoutParams(params);
}
}
//解析子布局
rInflateChildren(parser, temp, attrs, true);
//如果root!=null,且attachToRoot==true,则自动将布局添加到root中,并设置布局参数
if (root != null && attachToRoot) {
root.addView(temp, params);
}
//当root==null或者attachToRoot==false,则直接返回View对象
if (root == null || !attachToRoot) {
result = temp;
}
}
} catch (XmlPullParserException e) {
final InflateException ie = new InflateException(e.getMessage(), e);
ie.setStackTrace(EMPTY_STACK_TRACE);
throw ie;
} catch (Exception e) {
final InflateException ie = new InflateException(
getParserStateDescription(inflaterContext, attrs)
+ ": " + e.getMessage(), e);
ie.setStackTrace(EMPTY_STACK_TRACE);
throw ie;
} finally {
mConstructorArgs[0] = lastContext;
mConstructorArgs[1] = null;
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
return result;
}
}
案例说明
layout_btn
<?xml version="1.0" encoding="utf-8"?>
<Button xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="200dp"
android:layout_height="200dp"
android:orientation="vertical"
android:text="hello" />
当 root == null
View view = layoutInflater.inflate(R.layout.layout_btn, null);
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
linearLayout.addView(view);
当 root != null && attachToRoot == true
View view = layoutInflater.inflate(R.layout.layout_btn, linearLayout, true);
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
当 root != null && attachToRoot == false
View view = layoutInflater.inflate(R.layout.layout_btn, linearLayout, false);
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
linearLayout.addView(view);