这里只讨论 LayoutInflater1infalte() 方法。

inflate(int resource, ViewGroup root, boolean attachToRoot);

第一个参数xml布局资源索引,第二个参数指的是加载布局的root。

attachToRoot为true,这个布局会被解析并加载在root下面,如果为false,则会依照root去解析该xml并返回view,但是这个view不会被加载到root里。把xml解析了,并依照root的类型给生成的view set一个LayoutParams ,但不将其add到root里。

我们通过看源码可以发现两个参数的方法最终调用的也是三个参数的方法,比如:

public View inflate(int resource, ViewGroup root) {
    return inflate(resource, root, root != null);
}

然后是前人总结的内容:

  1. 如果root为null,attachToRoot将失去作用,设置任何值都没有意义。
  2. 如果root不为null,attachToRoot设为true,则会给加载的布局文件的指定一个父布局,即root。
  3. 如果root不为null,attachToRoot设为false,则会将布局文件最外层的所有layout属性进行设置,当该view被添加到父view当中时,这些layout属性会自动生效。
  4. 在不设置attachToRoot参数的情况下,如果root不为null,attachToRoot参数默认为true。

结合实例来理解:

title.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/title_bg">
    <Button
        android:id="@+id/title_back"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_margin="5dp"
        android:background="@drawable/back_bg"
        android:text="Back"
        android:textColor="#fff"/>
    <TextView
        android:id="@+id/title_text"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_weight="1"
        android:gravity="center"
        android:text="Title Text"
        android:textColor="#fff"
        android:textSize="24sp"/>
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_margin="5dp"
        android:background="@drawable/edit_bg"
        android:text="Edit"
        android:textColor="#fff"/>

</LinearLayout>

TitleLayout.java

package com.example.uicustomviews;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;

import androidx.annotation.Nullable;

public class TitleLayout extends LinearLayout {
    public TitleLayout(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        View inflate = LayoutInflater.from(context).inflate(R.layout.title, this);
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <com.example.uicustomviews.TitleLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

</LinearLayout>

MainActivity.java

package com.example.uicustomviews;

import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ActionBar actionBar = getSupportActionBar();

        if (actionBar != null) {
            actionBar.hide();
        }

    }
}

这个示例的功能是展示动态引入标题栏的功能的,我们观察上面的 TitleLayout.java 代码,其传入的 root 参数是 this,即当前这个类,第三个参数默认是true,观察运行结果:

android inflate方法 安卓inflate方法_xml

而将第三个参数设置为false的话,则加载不出来标题栏:

View inflate = LayoutInflater.from(context).inflate(R.layout.title, this, false);

android inflate方法 安卓inflate方法_android_02

然后,我们再添加一行代码:

View inflate = LayoutInflater.from(context).inflate(R.layout.title, this, false);
this.addView(inflate);

这时,我们发现标题栏又可以正常显示了:

android inflate方法 安卓inflate方法_xml

结合这个,我们就不难理解上面的解释了——attachToRoot为true,这个布局会被解析并加载在root下面,如果为false,则会依照root去解析该xml并返回view,但是这个view不会被加载到root里。把xml解析了,并依照root的类型给生成的view set一个LayoutParams ,但不将其add到root里。

其他的情况以此类推就好。

批注:我觉得 inflate 在英文中有膨胀、扩充的意思,在这里可以解释为扩充一个布局出来的意思。