深入理解 LayoutInflater.inflate() 方法

本文详尽分析了Android中LayoutInflater.inflate()方法的参数,包括不同参数组合的影响,如根节点非merge时的四种情况及根节点为merge时的情况。通过对源码的解读,解释了各参数的作用,如根节点布局参数的处理。并举例说明在自定义控件、Fragment、RecyclerView和AlertDialog填充布局的实际应用场景中如何使用inflate()方法。
摘要由CSDN通过智能技术生成

1. 前言

在开发中,对于 LayoutInflaterinflate() 方法,它的作用是把 xml 布局转换为对应的 View 对象,我们几乎天天在用。但是,对于 inflate() 方法的参数,是比较令人迷惑的。即便是看了文档的解释,依然不能解开迷惑。

或许,每次使用只能采取试验的办法,也不会非常影响开发;或许,记住在具体场景该怎么传递具体的参数,而不明所以。

我们不应该忽略细节:

public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot)
  • ViewGroup root 参数的作用是什么,为什么有时候可以传 null,有时候却不可以?
  • boolean attachToRoot 参数什么时候传 true,什么时候传 false?为什么有时候传递 true 会崩溃?
  • 为什么有的时候 xml 中根节点设置的布局参数却不生效?

这篇文章主要是说明 inflate() 方法参数的含义,以及在具体场景的使用。

2. 正文

2.1 inflate() 方法分析

LayoutInflater 类中,有几个重载的 inflate() 方法:

public View inflate(@LayoutRes int resource, @Nullable ViewGroup root)
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot)
public View inflate(XmlPullParser parser, @Nullable ViewGroup root)
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot)

大家在实际开发中,使用比较多的应该是前两个。

它们的调用关系(箭头指向表示调用方向)如下:

从图中可以看出前三个最终调用的都是最后一个:

public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot)

那么现在,我们集中精力去看最后一个方法。把最后一个方法搞清楚就可以了,就可以搞懂另外三个了。

这个方法中的第一个参数 XmlPullParser parser,查看源码,可以看到:

final Resources res = getContext().getResources();
XmlResourceParser parser = res.getLayout(resource);

是由 xml 转换而来的,用来对 xml 进行解析的一个类。

好了,我们已经了解了第一个参数的含义,就是传递要转换的 xml 布局过来。

接着看后面的两个参数:@Nullable ViewGroup rootboolean attachToRoot。需要注意的是 ViewGroup root 前面有一个注解 @Nullable,表示 ViewGroup root 这个参数可以为 null

这两个参数的取值组合有几种呢?4 种。

取值组合 ViewGroup root boolean attachToRoot
第一组 notNull false
第二组 notNull true
第三组 null false
第四组 null true

不同的取值组合,对于最后的返回值 View 有什么影响呢?

到这里,我们需要去查看一下 inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) 方法的源码:

public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
   
    synchronized (mConstructorArgs) {
   
        final Context inflaterContext = mContext;
        final AttributeSet attrs = Xml.asAttributeSet(parser);
        View result = root;
        advanceToRootNode(parser);
        // 获取根节点的名字,比如 LinearLayout, FrameLayout 等。
        final String name = parser.getName();
        if (TAG_MERGE.equals(name)) {
   
        	// 根节点的名字是 merge
            if (root == null || !attachToRoot) {
   
                throw new InflateException("<merge /> can be used only with a valid "
                        + "ViewGroup root and attachToRoot=true");
            }
            rInflate(parser, root, inflaterContext, attrs, false);
        } else {
   
            // Temp is the root view that was found in the xml
            // 获取 xml 布局的根 View 对象,比如 LinearLayout 对象,FrameLayout 对象等。
            final View temp = createViewFromTag(root, name, inflaterContext, attrs);
            ViewGroup.LayoutParams params = null;
            if (root != null) {
   
                // Create layout params that match root, if supplied
                params = root.generateLayoutParams(attrs);
                if (!attachToRoot) {
   
                    // Set the layout params for temp if we are not
                    // attaching. (If we are, we use addView, below)
                    temp.setLayoutParams(params);
                }
            }
            // Inflate all children under temp against its context.
            rInflateChildren(parser, temp, attrs, true);
            // We are supposed to attach all the views we found (int temp)
            // to root. Do that now.
            if (root != null && attachToRoot) {
   
                root.addView(temp, params);
            }
            // Decide whether to return the root that was passed in or the
            // top view found in xml.
            if (root == null || !attachToRoot) {
   
                result = temp;
            }
        }
        return result;
    }
}

我们先不考虑根节点为 merge 的情况,因为这是比较特殊的根节点。先按照一般的情况来分析,有助于解决普遍的问题。

2.1.1 根节点不是 merge 时,第一组取值情况分析

根节点是否是 merge 取值组合 ViewGroup root boolean attachToRoot
第一组 notNull false

在第 5 行 View result = root;root 的值赋值给 View result,那么有 result 的值是 notNull

在第 21 行 if (root != null) 的判断语句判断为 true,不能进入 if 语句。

在第 23 行 params = root.generateLayoutParams(attrs);,通过 root 来获取根节点的布局参数 ViewGroup.LayoutParams 对象,也就是说,把 xml 中的根节点的 layout_ 开头的属性,如layout_widthlayout_height 对应的值转为布局参数对象中的字段值,如widthheight 值。对应的源码在 ViewGroup 中如下:

public LayoutParams generateLayoutParams(AttributeSet attrs) 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值