LayoutInflater (layout service)


Introduction to this section:

This section continues to introduce the LayoutInflater (layout service) in the Android system service. When it comes to layout, everyone immediately What you may think of is to write a layout xml, then call Activity's setContentView() to load the layout, and then display it. On the screen, right? In fact, the bottom layer is still the LayoutInflater, which is parsed using Android's built-in Pull parser. layout. Generally, it is more commonly used in Android to dynamically load layouts or add controls. In this section, we will learn how to use it in actual development. Some usage~

Official API Document:LayoutInflater


1. Related introduction of LayoutInflater


1) What the hell is Layout?

Answer: A system service used to load layout is to instantiate the View object corresponding to the Layout XML file. It cannot be used directly. You need to use the getLayoutInflater() method or the getSystemService() method to obtain the content bound to the current Context. LayoutInflater instance!


2) Usage of LayoutInflater

①Three methods to obtain LayoutInflater instance:

LayoutInflater inflater1 = LayoutInflater.from(this);  
LayoutInflater inflater2 = getLayoutInflater();  
LayoutInflater inflater3 = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);

PS: The latter two actually use the first method at the bottom~

②Loading layout method:

public View inflate (int resource, ViewGroup root, boolean attachToRoot) The three parameters of this method are:

① The resource id corresponding to the layout to be loaded

② Nest another layer of parent layout outside the layout. If not needed, write Null is fine!

③ Whether to set a root layout as the outermost layer of the loaded layout file. If this parameter is not set, If root is not null, it defaults to true If root is null, attachToRoot has no effect! If root is not null and attachToRoot is true, a root layout will be nested in the outermost layer of the loaded layout file; If it is false, root will lose its function! The simple understanding is: Whether to add a root outer container for the loaded layout~!


##③Set related properties through LayoutInflater.LayoutParams:

For example, RelativeLayout can also add rules through the addRule method, which is to set the position: does it refer to the parent container? Or refer to the child control? Or set margin, etc., it’s up to you~


2. Pure Java code loading layout

We have long been accustomed to using XML to generate what we need layout, but in some specific cases we We need to use Java code to dynamically add components or layouts to our layout!

But it is not recommended that you completely use Java code to write Android page layout. The first point is that there will be a lot of code. It is easy to mess up and is not conducive to business separation. We still recommend using xml to complete the layout, and then pass Java code modifies the components inside. Of course, sometimes you may need to use Java to dynamically add components!

Pure Java code loading layout process


——Step 1

Create container:LinearLayout ly = new LinearLayout(this);

Create component:Button btnOne = new Button(this);

— —Step 2:

You can set related properties for the container or component: For example: LinearLayout, we can set the arrangement direction of the component: ly.setOrientation(LinearLayout.VERTICAL);And the component can also be: For example, Button: btnOne.setText("Button 1");For the method of setting attributes, please refer to the Android API. Usually, the attributes set by xml only need to be added in front: set, such as setPadding(left, top, right, bottom) ;

——Step 3:

Add the component or container to the container. At this time we may need to set the adding position of the component, or set its size : We need to use a class: LayoutParams, we can think of it as an information package of the layout container! Encapsulation position and size A class waiting for information! First demonstrate the method of setting the size: (the previous LinearLayout can be changed according to different containers)

LinearLayout.LayoutParams lp1 = new LinearLayout.LayoutParams(  
        LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);

is very simple, and then comes to the setting position. When setting the position, we usually consider The only thing is RelativeLayout! At this time, the addRule() method of LayoutParams is used! You can add multiple addRule()! Set the position of the component in the parent container,

For example, Set the alignment method of the component:

RelativeLayout rly = new RelativeLayout(this);  
RelativeLayout.LayoutParams lp2 = new RelativeLayout.LayoutParams(  
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);  
lp2.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);  
Button btnOne = new Button(this);  
rly.addView(btnOne, lp2);

Refer to the alignment method of other components: (One disadvantage is that you have to manually set an id for the reference component, which is manual!!!!) For example: After setting btnOne to be centered, let BtnTwo be located below btnOne and to the right of the parent container!

public class MainActivity extends Activity {  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        RelativeLayout rly = new RelativeLayout(this);  
        Button btnOne = new Button(this);  
        btnOne.setText("按钮1");  
        Button btnTwo = new Button(this);  
        btnTwo.setText("按钮2");  
        // 为按钮1设置一个id值  
        btnOne.setId(123);  
        // 设置按钮1的位置,在父容器中居中  
        RelativeLayout.LayoutParams rlp1 = new RelativeLayout.LayoutParams(  
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);  
        rlp1.addRule(RelativeLayout.CENTER_IN_PARENT);  
        // 设置按钮2的位置,在按钮1的下方,并且对齐父容器右面  
        RelativeLayout.LayoutParams rlp2 = new RelativeLayout.LayoutParams(  
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);  
        rlp2.addRule(RelativeLayout.BELOW, 123);  
        rlp2.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);  
        // 将组件添加到外部容器中  
        rly.addView(btnTwo, rlp2);  
        rly.addView(btnOne, rlp1);  
        // 设置当前视图加载的View即rly  
        setContentView(rly);  
    }  
}

——step 4:

Call the setContentView() method to load the layout Just the object! In addition, if you want to remove a View in a container, you can call the container.removeView(component to be removed);

Run screenshot:

1.png


3. Java code dynamically adds controls or xml layout

The second point we explained is to use pure Java code to load the layout. In practice It is not used much, more often it is dynamic. Add View control and dynamically load XML layout!

1) Java code dynamically adds View

There are two ways to dynamically add components. The difference lies in whether you need to setContentView(R.layout .activity_main); The following demonstrates two different writing methods for adding a Button:

Write a layout file first: activity_main.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:id="@+id/RelativeLayout1"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent" >  
  
    <TextView   
        android:id="@+id/txtTitle"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:text="我是xml文件加载的布局"/>  
</RelativeLayout>

The first method is not SetContentView() is required to load the layout file first:

public class MainActivity extends Activity {  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        Button btnOne = new Button(this);  
        btnOne.setText("我是动态添加的按钮");  
        RelativeLayout.LayoutParams lp2 = new RelativeLayout.LayoutParams(    
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);    
        lp2.addRule(RelativeLayout.CENTER_IN_PARENT);    
        LayoutInflater inflater = LayoutInflater.from(this);  
        RelativeLayout rly = (RelativeLayout) inflater.inflate(  
                R.layout.activity_main, null)  
                .findViewById(R.id.RelativeLayout1);  
        rly.addView(btnOne,lp2);  
        setContentView(rly);  
    }  
}

The second type does not require setContentView() to load the layout file first:

public class MainActivity extends Activity {  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        Button btnOne = new Button(this);  
        btnOne.setText("我是动态添加的按钮");  
        RelativeLayout.LayoutParams lp2 = new RelativeLayout.LayoutParams(    
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);    
        lp2.addRule(RelativeLayout.CENTER_IN_PARENT);    
        RelativeLayout rly = (RelativeLayout) findViewById(R.id.RelativeLayout1);  
        rly.addView(btnOne,lp2);  
    }  
}

Analysis summary

The code is very simple. After creating the button, we created a LayoutParams object to set the size of the Button. The position of the Button is set through the addRule() method!

The first method: Load the activity_main layout through the inflate() method of LayoutInflate, and obtain the outer container. Then addView adds the button to the container, and finally setContentView();

Second method: Because we have loaded the layout through the setContetView() method, at this time we can pass findViewById finds the outer container, then addView, and finally setContentView()!

In addition, the view node set by setContentView() is the root node of the entire XML!


2) Java code dynamically loads xml layout

Next, let’s change it, this time loading an xml file!Dynamicly add xml file! First write down the main layout file and the dynamically loaded layout file:

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/RelativeLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <Button
        android:id="@+id/btnLoad"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="动态加载布局"/></RelativeLayout>

inflate.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"  
    android:gravity="center"  
    android:orientation="vertical"  
    android:id="@+id/ly_inflate" >  
  
    <TextView  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:text="我是Java代码加载的布局" />  
  
    <Button  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:text="我是布局里的一个小按钮" />  
  </LinearLayout>

Then go to our MainActivity.java Dynamically load the xml layout here:

public class MainActivity extends Activity {  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        //获得LayoutInflater对象;  
        final LayoutInflater inflater = LayoutInflater.from(this);    
        //获得外部容器对象  
        final RelativeLayout rly = (RelativeLayout) findViewById(R.id.RelativeLayout1);  
        Button btnLoad = (Button) findViewById(R.id.btnLoad);  
        btnLoad.setOnClickListener(new OnClickListener() {  
            @Override  
            public void onClick(View v) {  
                //加载要添加的布局对象  
                LinearLayout ly = (LinearLayout) inflater.inflate(  
                        R.layout.inflate, null, false).findViewById(  
                        R.id.ly_inflate);  
                //设置加载布局的大小与位置  
                RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(    
                        LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);    
                lp.addRule(RelativeLayout.CENTER_IN_PARENT);    
                rly.addView(ly,lp);  
            }  
        });  
    }  
}

Run the screenshot :

2.gif

Code analysis:

①Get the container object:

final RelativeLayout rly = (RelativeLayout) findViewById(R.id.RelativeLayout1);

②Get the Inflater object and load it at the same time In the xml of the added layout, find the outermost root node through findViewById

final LayoutInflater inflater = LayoutInflater.from(this);
LinearLayout ly = (LinearLayout) inflater.inflate(R.layout.inflate, null, false)
   .findViewById(R.id.ly_inflate);

③Set the size and position information for this container:

RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(  
               LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);  
       lp.addRule(RelativeLayout.CENTER_IN_PARENT);

④Add to the outer container:

rly.addView(ly,lp);

4.LayoutInflater’s inflate() method source code

Finally provide the inflate of LayoutInflater The source code of the () method, if you are interested, you can take a look~, it is actually just Pull analysis~

public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {    
    synchronized (mConstructorArgs) {    
        final AttributeSet attrs = Xml.asAttributeSet(parser);    
        mConstructorArgs[0] = mContext;    
        View result = root;    
        try {    
            int type;    
            while ((type = parser.next()) != XmlPullParser.START_TAG &&    
                    type != XmlPullParser.END_DOCUMENT) {    
            }    
            if (type != XmlPullParser.START_TAG) {    
                throw new InflateException(parser.getPositionDescription()    
                        + ": No start tag found!");    
            }    
            final String name = parser.getName();    
            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, attrs);    
            } else {    
                View temp = createViewFromTag(name, attrs);    
                ViewGroup.LayoutParams params = null;    
                if (root != null) {    
                    params = root.generateLayoutParams(attrs);    
                    if (!attachToRoot) {    
                        temp.setLayoutParams(params);    
                    }    
                }    
                rInflate(parser, temp, attrs);    
                if (root != null && attachToRoot) {    
                    root.addView(temp, params);    
                }    
                if (root == null || !attachToRoot) {    
                    result = temp;    
                }    
            }    
        } catch (XmlPullParserException e) {    
            InflateException ex = new InflateException(e.getMessage());    
            ex.initCause(e);    
            throw ex;    
        } catch (IOException e) {    
            InflateException ex = new InflateException(    
                    parser.getPositionDescription()    
                    + ": " + e.getMessage());    
            ex.initCause(e);    
            throw ex;    
        }    
        return result;    
    }    
}

Summary of this section:

This section gives Everyone explained LayoutInflater (layout service) in Android, as well as dynamic loading of Views and controls. Related things, I believe it will be helpful to friends who are new to controls~Okay, that’s all, thank you~3.gif