View.inflate和LayoutInflater.inflate的区别

其实View.inflate(context, layoutResId, root)是对LayoutInflater.from(context).inflate(layoutResId, root, attachToRoot)的封装

最终会调用下面的方法,这将根据不同的传入参数得到不同的结果

    public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
        synchronized (mConstructorArgs) {
            
            View result = root;

            ...

                    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);
                        }
                    }

                    if (root != null && attachToRoot) {
                        root.addView(temp, params);
                    }
                    
                    if (root == null || !attachToRoot) {
                        result = temp;
                    }
                }

            return result;
        }
    }
复制代码

当调用View.inflate(context, layoutResId, root)时会调用LayoutInflater.inflate(layoutResId, root)然后调用LayoutInflater.inflate(layoutResId, root, root != null)

即调用View.inflate(context, layoutResId, root)root == null实际等价于LayoutInflater.from(context).inflate(layoutResId, null, false),而root != null时等价于LayoutInflater.from(context).inflate(layoutResId, root, true),所以说讨论View.inflate(context, layoutResId, root)LayoutInflater.from(context).inflate(layoutResId, root, attachToRoot)的异同实际上就是讨论不同rootattachToRoot传入参数情况下的影响。

1 在直接代码上表现的差异

1.1 root == nullattachToRoot == false(其实只要rootnullattachToRoot取何值都一样,这里取false

当调用View.inflate(context, layoutResId, null)时即LayoutInflater.from(context).inflate(layoutResId, null, false),将执行文首贴出的inflate方法,执行相应逻辑

  View result = root;
    
  if (root == null || !attachToRoot) {
      result = temp;
  }

  return result;
复制代码

return的是view他自己,view是解析layoutResId布局生成的View。

1.2 root != nullattachToRoot == true

当调用View.inflate(context, layoutResId, null)时即LayoutInflater.from(context).inflate(layoutResId, root, true),将执行文首贴出的inflate方法,执行相应逻辑

    View result = root;

    if (root != null) {
        // Create layout params that match root, if supplied
        params = root.generateLayoutParams(attrs);
    }

    if (root != null && attachToRoot) {
        root.addView(temp, params);
    }

    return result;
复制代码

给view设置解析得到的LayoutParams(含layoutResId对应xml中声明的宽高信息)并添加到root,return的是view的父布局root。

1.3 root != nullattachToRoot == false

只能直接调用LayoutInflater.from(context).inflate(layoutResId, root, false),View中的inflater静态方法无法做到,在文首贴出的inflate方法中执行的逻辑是

    View result = root;

    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);
        }
    }

    return result;
复制代码

给view设置解析得到的LayoutParams(含layoutResId对应xml中声明的宽高信息),return的是view他自己。

2 流程和控制上的差异

由此可以看出的rootattachToRoot参数的差异将决定view是否将会添加到root,是否会给View设置解析得到的LayoutParams,甚至是返回值。

但是这里影响最大的是是否给view设置解析好的LayoutParams,也是我们最关注的差异。为什么?

经过前面的分析知道,return分为view他自身和view的父布局root两种情况,我们在做引用的时候肯定要明确什么时候返回什么。

其实这对View.inflateLayoutInflater.inflate而言并没有差别,这两种情况他们都可能返回这两种值。

view是否添加到root是由attachToRoot参数控制影响的,这是开发者自行传入控制的参数。开发者明确知道想要控制view被添加到容器的时机、对象,添加的时机就是inflate的时候(attachToRoot == true)或者其他任何时候(attachToRoot == false

问题来了,传入attachToRoot == true,inflater的时候把就view添加到Root包含解析得到LayoutParams信息,符合我们的预期(我们在布局xml中声明的layout_widthlayout_height宽高值)。而传入attachToRoot == false,root也为null,在view中没有解析的LayoutParams信息,等我们自己addView时会给一个默认的LayoutParams(WRAP_CONTENT, WRAP_CONTENT),覆盖在布局xml声明的宽高值,导致我们的设置失效。

总结

到现在我们就知道,为什么一些有经验的人会说不要用View.inflate而是用LayoutInflater.inflate,主要是View.inflate(context, layoutResId, null)会让我们在layoutResId布局中声明的宽高信息无效(MATCH_PARENT或具体宽高),而用LayoutInflater.from(context).inflate(layoutResId, root, false)替代,后者没有这个问题。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享