美文网首页
LayoutInflater.inflate参数配置

LayoutInflater.inflate参数配置

作者: EnzoRay | 来源:发表于2021-12-09 13:41 被阅读0次

    在使用自定义View的过程中经常需要使用LayoutInflater.inflate()方法添加布局文件,如下是我们要添加的布局:layout_item.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:background="@color/teal_200"
        android:layout_width="200dp"
        android:layout_height="200dp">
    
        <Button
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button" />
    </LinearLayout>
    

    activity_main.xml布局如下:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:id="@+id/root"
        tools:context=".MainActivity">
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello World!"/>
    
    </LinearLayout>
    

    MainActivity.java如下:

    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            LinearLayout mRoot = findViewById(R.id.root);
            View view = LayoutInflater.from(this).inflate(R.layout.layout_item, null);
            mRoot.addView(view);
    
        }
    }
    

    这样就可以把layout_item.xml布局添加到activity_main.xml布局的LinearLayout下面了,下图是运行后的显示效果:



    发现layout_item.xml的根布局LinearLayout的layout_width="200dp"和layout_height="200dp"失效了,这是什么原因?

    我们进入inflate()方法一探究竟,该方法最终会调用如下3个参数的inflate方法:

        public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
            synchronized (mConstructorArgs) {
                Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");
    
                final Context inflaterContext = mContext;
                final AttributeSet attrs = Xml.asAttributeSet(parser);
                Context lastContext = (Context) mConstructorArgs[0];
                mConstructorArgs[0] = inflaterContext;
                View result = root;
    
                try {
                    // Look for the root node.
                    int type;
                    while ((type = parser.next()) != XmlPullParser.START_TAG &&
                            type != XmlPullParser.END_DOCUMENT) {
                        // Empty
                    }
    
                    if (type != XmlPullParser.START_TAG) {
                        throw new InflateException(parser.getPositionDescription()
                                + ": No start tag found!");
                    }
    
                    final String name = parser.getName();
    
                    if (DEBUG) {
                        System.out.println("**************************");
                        System.out.println("Creating root view: "
                                + name);
                        System.out.println("**************************");
                    }
    
                    if (TAG_MERGE.equals(name)) {
                        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
                        final View temp = createViewFromTag(root, name, inflaterContext, attrs);
    
                        ViewGroup.LayoutParams params = null;
    
                        if (root != null) {
                            if (DEBUG) {
                                System.out.println("Creating params from root: " +
                                        root);
                            }
                            // 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 (DEBUG) {
                            System.out.println("-----> start inflating children");
                        }
    
                        // Inflate all children under temp against its context.
                        rInflateChildren(parser, temp, attrs, true);
    
                        if (DEBUG) {
                            System.out.println("-----> done inflating children");
                        }
    
                        // 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;
                        }
                    }
    
                } catch (XmlPullParserException e) {
                    final InflateException ie = new InflateException(e.getMessage(), e);
                    ie.setStackTrace(EMPTY_STACK_TRACE);
                    throw ie;
                } catch (Exception e) {
                    final InflateException ie = new InflateException(parser.getPositionDescription()
                            + ": " + e.getMessage(), e);
                    ie.setStackTrace(EMPTY_STACK_TRACE);
                    throw ie;
                } finally {
                    // Don't retain static reference on context.
                    mConstructorArgs[0] = lastContext;
                    mConstructorArgs[1] = null;
    
                    Trace.traceEnd(Trace.TRACE_TAG_VIEW);
                }
    
                return result;
            }
        }
    

    可以看到这里是使用Android提供的pull解析方式来解析布局文件的,其中TAG_MERGE表示<merge/>标签,createViewFromTag是根据节点名来创建View对象的,里面会先判断mFactory2 != null是否成立,如果成立,调用mFactory2来创建View,否则使用下面这段代码来反射创建View对象:

    if (-1 == name.indexOf('.')) {
            view = onCreateView(parent, name, attrs);
    } else {
             view = createView(name, null, attrs);
    }
    

    我们回到调用createViewFromTag的位置往下,这里会先判断root是否为空,如果不为空,通过下面这段代码给temp设置布局参数,temp即所要添加的布局的根布局:

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

    继续往下,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;
                        }
    

    如果root不为null且attachToRoot为true,则通过root.addView(temp, params)添加布局;如果root为null或attachToRoot为false,直接返回temp。

    看到这里大家应该明白为什么layout_item.xml的根布局的大小失效了,原因就是因为root为null,直接返回了temp。如果想要layout_item.xml的根布局的大小不失效,root就不能为null,改为View view = LayoutInflater.from(this).inflate(R.layout.layout_item, mRoot, false)即可。

    下面总结一下:
    对于inflate(int resource, ViewGroup root, boolean attachToRoot)的参数:
    1.如果root为null,不论attachToRoot为true或false,所添加的布局的根布局将失效;
    2.如果root不为null且attachToRoot为true,待添加的布局将自动添加到root中;
    3.如果root不为null且attachToRoot为false,待添加的布局不会自动添加到root,此时还需要手动addView();

    相关文章

      网友评论

          本文标题:LayoutInflater.inflate参数配置

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