美文网首页
是Android的自定义View-进阶知识-inflate方法的

是Android的自定义View-进阶知识-inflate方法的

作者: redrain39 | 来源:发表于2021-01-11 18:12 被阅读0次

    前言

    在自定义View中其实还有一个十分常见的类是我们经常会使用到的那就是LayoutInflater。为什么会说它常用呢?还记得之前的文章有讲过,自定义View有一种实现方式是通过多个已有控件进行组合来实现的,那么这就需要通过LayoutInflaterinflate方法对定义好的xml文件进行转译,对,没错,是转译,前文中提到的这个方法其原理就是对xml文件进行读取,进而转化为实际的布局。

    关于LayoutInflaterinflate方法其实用一直在用,也都知道它最终是用来获取View对象的,但是这个方法最让人搞不清楚的是它的参数,所以本文主要的内容是来讲解一下其参数的具体含义。

    方法分析

    一般的,我们是这样使用LayoutInflaterinflate方法的:

    val view = LayoutInflater.from(context).inflate(R.layout.view_custom, this)
    

    通过如上的方法,我们就可以获取到我们所需要布局的View对象,那么我们进入到这个方法中去:

    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) {
        final Resources res = getContext().getResources();
    
        View view = tryInflatePrecompiled(resource, res, root, attachToRoot);
        if (view != null) {
            return view;
        }
        XmlResourceParser parser = res.getLayout(resource);
        try {
            return inflate(parser, root, attachToRoot);
        } finally {
            parser.close();
        }
    }
    

    这个方法所做的是将xml资源文件转化为一个Xml的解析器进而去进行下一步操作,此外这里二参方法还有另外一个重载方法:

    public View inflate(XmlPullParser parser, @Nullable ViewGroup root) {
        return inflate(parser, root, root != null);
    }
    

    其指向的也是接下来这个三参方法,说明方法调用到最后都会来到下面这个方法来执行核心逻辑:

    在分析前,我们要明确我们分析的目的是理解方法参数的含义,从方法的调用顺序来看,主要关注的是rootattachToRoot这两个参数。

    // 省略了安全判断和部分无用代码
    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();
    
                ···
                
                // 获取当前根视图
                final View temp = createViewFromTag(root, name, inflaterContext, attrs);
    
                ViewGroup.LayoutParams params = null;
                // root != null
                if (root != null) {
                    // 如果attachToRoot为false的话只会对当前布局设置其父布局的相关属性配置,但并不会将View add到父布局上
                    params = root.generateLayoutParams(attrs);
                    if (!attachToRoot) {
                        temp.setLayoutParams(params);
                    }
                }
    
                // root != null 同时attachToRoot为true,会在应用布局配置的同时将View添加到父布局上去
                if (root != null && attachToRoot) {
                    root.addView(temp, params);
                }
    
                // root == null 不做任何操作,直接返回了创建好的View
                if (root == null || !attachToRoot) {
                    result = temp;
                }
                
            }
    
            return result;
        }
    }
    

    简单地对方法地调用做了分析,其中源码具体实现没有展开,只追了我们关注那部分逻辑,下面根据追源码地结果来进行一下总结:

    • root为null时,attachToRoot值失去作用,会返回一个View对象,但是不会有任何的操作,也不会依附于某个ViewGroup进行展示
    • root不为null,attachToRoot为true,会将View加载到指定的父布局上,即root上
    • root不为null,attachToRoot为false,view最外层的layout相关属性会配置,但是view不会加载到任何布局上,只用手动add后layout相关属性才会生效

    以上就是关于inflate这个方法相关的解惑,重点分析了不同参数所最终实现的效果是怎么样的,一般的情况直接使用二参方法去获取View对象就可以啦,其它的根据实际场景去针对性的选择使用。

    相关文章

      网友评论

          本文标题:是Android的自定义View-进阶知识-inflate方法的

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