Android LayoutInflater inflate()

作者: d74f37143a31 | 来源:发表于2018-12-13 22:26 被阅读9次

    之前在动态加载一个布局时用 View.inflate() 去加载,最后没加载出来,换为 LayoutInflater.from(mContext).inflate() 之后加载成功。具体场景我没记清了,但是我们可以通过了解这两个方式加载布局的方法来规避以后 使用可能出现的问题。

    既然是由 LayoutInflater.from(mContext).inflate() 引出的问题那就从怎么使用开始去一步一步深挖。

    LayoutInflater.from(this).inflate()

    有 4 个构造方法,前面三个构造方法最终都会调用最后一个构造方法 inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) 进行布局的解析。

    它的四个构造方法如下:

    
    第一个构造方法
    
    public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
    
        return inflate(resource, root, root != null);
    
    }
    
    第二个构造方法
    
    public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
     // 真正实现的过程太长,这里就不贴代码了,可自行去查看源码
    }
    
    第三个构造方法
    
    public View inflate(XmlPullParser parser, @Nullable ViewGroup root) {
    
        return inflate(parser, root, root != null);
    
    }
    
    第四个构造方法
    
    public View inflate(XmlPullParser parser, @Nullable ViewGroup root, 
                    boolean attachToRoot) {
        // 真正实现的过程太长,这里就不贴代码了,可自行去查看源码
    }
    
    

    我们常用的是第一个构造方法,但是第一个构造方法会调用第二个构造函数,所以我们 直接分析第二个构造方法。

    它的构造方法参数介绍如下所示:

    public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, 
                      boolean attachToRoot) {
    }
    

    参数解释:

    • @param resource 布局文件id (例如R.layout.main_page
    • @param root
      • 如果参数三 attachToRoottrue, 则参数二是作为参数一中布局文件的父控件
      • 如果参数三 attachToRootfalse, 则参数二是作为提供一组 LayoutParams 值的对象
    • @param attachToRoot 指定参数一的布局 View 对象是否要作为 第二个参数控件上作为子控件

    返回值:

    • @returnroot 不为空,且第 attachToRoottrue,则返回root作为根布局,否则,返回参数一 view对象的根布局 作为根布局

    LayoutInflater.from(mContext).inflate() 小结

    来源于文末 郭神 博客参考

    • 如果rootnullattachToRoot将失去作用,设置任何值都没有意义,加载的布局文件最外层的所有layout属性会失效,由父布局来重新指定.

    实例验证
    图一是rootnullattachToRoot=true 修改 R.layout.inflate_test_btn 的宽度为300dp的结果,很明显没修改成功。在测试过程中我修改了 attachToRoot=false,结果还是不变。

    图一.png

    图二是修改了父布局宽度为300dp

    图二.png

    验证结果正确:由父布局指定。

    • 如果root不为nullattachToRoot不论是truefalse,加载的布局文件最外层的所有layout属性都有效,唯一的不同是:

      • attachToRoottrue时,会自动调用root.addView(view, params),最后返回root

    实例验证

    resourceR.layout.inflate_test_btnattachToRoottrue, rootcontentLayout ,完整调用如:LayoutInflater.from(this).inflate(R.layout.inflate_test_btn, contentLayout, true);

    这时候如果不处理,会崩溃:

    The specified child already has a parent. 
    You must call removeView() on the child's parent first.
    

    通过打印 parent 得到如下信息:

    onCreate: parent---->android.widget.LinearLayout{
    4016a11 V.E...... ......I. 0,0-0,0 #7f0d007e app:id/root_layout}
    

    原来还可以这样查看父布局。。
    根据提示我们只能先移除其它子view 再添加

    结合图三以及崩溃日志,可以证明会自动调用 root.addView(view, params)。

    图三.jpg

    验证结果正确:会自动调用 root.addView(view, params),最后返回 root。

    • attachToRootfalse时,会返回view,需手动调用root.addView(view, params).

    实例验证

    resourceR.layout.inflate_test_btnattachToRootfalse, rootcontentLayout ,完整调用如:LayoutInflater.from(this).inflate(R.layout.inflate_test_btn, contentLayout, false);

    通过打印 parent 得到如下信息:

    onCreate: parent---->null
    
            不会崩溃,可以正常添加, 而且父布局中的子 view 都存在
    

    图四可以证明 root.addView()是需要手动添加的.

    图四.png

    验证结果:需手动调用 root.addView(view, params)

    • 在不设置attachToRoot参数的情况下,如果root不为nullattachToRoot参数默认为true.

    实例验证

    resourceR.layout.inflate_test_btnattachToRoot不设置或者是设置为false, rootcontentLayout ,完整调用如:
    LayoutInflater.from(this).inflate(R.layout.inflate_test_btn, contentLayout, false);
    LayoutInflater.from(this).inflate(R.layout.inflate_test_btn, contentLayout,);

    LayoutInflater.from(this).inflate(R.layout.inflate_test_btn,contentLayout);
    
            会崩溃
    
    LayoutInflater.from(this).inflate(R.layout.inflate_test_btn,contentLayout,false);
    
            不会崩溃
    

    验证结果正确:如果 root 不为 null, attachToRoot 参数默认为 true.

    关于 View 类的 inflate 方法

    View.inflate是对 LayoutInflater inflate 的进一步封装,但是只实现了 LayoutInflater inflate 两个参数的构造方法,所以功能相对 LayoutInflater会弱一些。我们可以通过源码直接看出二者的关系。

    View.inflate实现的源码如下:

    参数介绍:
    context 表示上下文
    resource 表示要填充的 `xml` 文件
    root 填充成的 `view` 对象的根布局
    
    public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) {
    
        LayoutInflater factory = LayoutInflater.from(context);
    
        return factory.inflate(resource, root);
    
    }
    
    构造方法中调用 LayoutInflater.from(this).inflate 两个参数 的 inflate
    
    public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
    
        return inflate(resource, root, root != null);
    
    }
    
    

    参考

    Android LayoutInflater原理分析,带你一步步深入了解View(一)

    相关文章

      网友评论

        本文标题:Android LayoutInflater inflate()

        本文链接:https://www.haomeiwen.com/subject/hshihqtx.html