2.2 LayoutInflater 加载布局文件源码
2018-09-10 本文已影响20人
littlezan
LayoutInflater 加载布局文件源码
LayoutInflater是一个用于将xml布局文件加载为View或者ViewGroup对象的工具,我们可以称之为布局加载器。
获取LayoutInflater实例
有3种方式获取到取LayoutInflater实例
第一种
(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
第二种 是针对第一种的封装
LayoutInflater.from(context);
第三种 在Activity中,封装了获取LayoutInflater的接口
Activity.getLayoutInflater()
LayoutInflater 的使用创建View
创建View,有4个重载方式
inflate(int resource, ViewGroup root)
inflate(int resource, ViewGroup root, boolean attachToRoot)
inflate(XmlPullParser parser, ViewGroup root)
inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot)
一般常用的是前2种
方式 | 结果 |
---|---|
inflate( resourceId, rootView) | 将解析布局文件生成的View,添加到rootView中 addView(parseView, layoutParams) |
inflate( resourceId, null) | 创建不带LayoutParams的View 布局文件里顶层空间的LayoutParams将会失效 |
inflate( resourceId, null, false) | 同上 |
inflate( resourceId, rootView, false) | 创建带LayoutParams的View 布局文件里顶层空间的LayoutParams有效果 但是不会加入到rootView中 |
inflate( resourceId, rootView, true) | 同第一个 |
源码解析
LayoutInflate
|
|-inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot)
|
|-final View temp = createViewFromTag(root, name, inflaterContext, attrs);
|创建根节点View
|
|-if(root != nul) root.generateLayoutParams(attrs);
|根据根节点属性创建,根节点View的LayoutParams
|
|-if(!attachToRoot) temp.setLayoutParams(params);
|如果添加到rootView,设置布局文件根View的LayoutParams属性
|
|- rInflateChildren(parser, temp, attrs, true);
|加载布局文件中子View
|
|-if (root != null && attachToRoot) root.addView(temp, params);
|将布局文件中根节点View添加到rootView中
这里解释了,inflate重载方法中root和attachToRoot这两个参数的含义
LayoutInflate
|
|-View createViewFromTag(View parent, String name, Context context, AttributeSet attrs,boolean ignoreThemeAttr)
|根据布局文件节点名称创建View
|
|
|-if (mFactory2 != null) view = mFactory2.onCreateView(parent, name, context, attrs);
|1.优先mFactory2创建view
|
|-if (mFactory != null) view = mFactory.onCreateView(name, context, attrs);
|2.mFactory创建view
|
|-if (view == null && mPrivateFactory != null) view = mPrivateFactory.onCreateView(parent, name, context, attrs);
|3.mPrivateFactory创建view
|
|-view = createView(name, null, attrs);
|4.直接通过反射方式创建View
|
|-clazz = mContext.getClassLoader().loadClass(prefix != null ? (prefix + name) : name).asSubclass(View.class);
|-constructor = clazz.getConstructor(mConstructorSignature);
|-final View view = constructor.newInstance(args);
|通过反射创建View
如果继承自AppCompateActivity,mFactory2!=null,创建AppCompateTextView,等对象
LayoutInflate
|
|-rInflateChildren(parser, temp, attrs, true);
|加载子View
|
|-final View view = createViewFromTag(parent, name, context, attrs);
|创建子View
|
|-final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);
|生成子View LayoutParmas属性
|
|-rInflateChildren(parser, view, attrs, true);
|创建该节点下子View
|
|-viewGroup.addView(view, params);
|将子View添加到父View中
|
|-if (finishInflate) parent.onFinishInflate();
|结束递归rInflateChildren
rInflateChildren函数是一个根据布局文件的节点递归遍历生生成子View,并添加到View树中,
当某个节点下面的所有子节点View解析生成完成后,才会调起onFinishInflate回调
利用LayoutInflate替换布局文件中默认View
- 实现LayoutInflater.Factory2接口
public class TestLayoutFactory implements LayoutInflater.Factory2 {
private static final String TAG = "TestLayoutFactory";
private final AppCompatDelegate delegate;
public TestLayoutFactory(AppCompatDelegate delegate) {
this.delegate = delegate;
}
@Override
public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
if (TextUtils.equals("TextView", name)) {
return new CustomTextView(context, attrs);
}
return delegate.createView(parent, name, context, attrs);
}
@Override
public View onCreateView(String name, Context context, AttributeSet attrs) {
return null;
}
}
- 在AppCompatActivity的onCreate()方法中设置LayoutInfalte.Factory
override fun onCreate(savedInstanceState: Bundle?) {
LayoutInflaterCompat.setFactory2(layoutInflater, TestLayoutFactory(getDelegate()))
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_test_layout_factory)
}
一定要在super.onCreate(savedInstanceState)
代码之前设置,否则会报错:
Caused by: java.lang.IllegalStateException: A factory has already been set on this LayoutInflater
因为在调用父类的onCreate()方法中,已经创建了LayoutInfalte.Factory,再次创建的时候,就会报错了