Android LayoutInflater 布局服务

LayoutInflater ( 布局服务 ) 使用 Android 内置的 Pull 解析器来解析布局,一般用于动态加载布局或者添加控件

平时我们创建一个布局的 xml,然后调用 Activity 的 setContentView() 加载布局,然后显示 到屏幕上的过程,底层使用的就是 LayoutInflater

LayoutInflater

LayoutInflater 一个用于加载布局的系统服务,就是实例化与 Layout XML 文件对应的 View 对象

LayoutInflater 不能直接使用,需要通过 getLayoutInflater() 方法或 getSystemService() 方法获得与当前 Context 绑定的 LayoutInflater 实例

LayoutInflater 的方法

  1. 获取 LayoutInflater 实例的三种方法

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

    后面两个其实底层都会调用第一种方法

  2. 加载布局的方法

    public View inflate(int resource, ViewGroup root, boolean attachToRoot)
    

    参数说明

    参数 说明
    resource 要加载的布局对应的资源 id
    root 为该布局的外部再嵌套一层父布局,如果不需要的话,设置 null
    attachToRoot 是否为加载的布局文件的最外层套一层 root 布局

    对于参数 attachToRoot 不设置该参数的话

    1. 如果 root 不为 null,则默认为 true
    2. 如果 root 为 null,attachToRoot 就没有作用了
    3. root不为 null,attachToRoot 为 true 的情况下,会在加载的布局文件最外层嵌套一层 root布局
    4. root不为 null,attachToRoot 为 false 的情况下 则root 失去作用

    简单的说,就是 是否为加载的布局添加一个root的外层容器

  3. 通过 LayoutInflater.LayoutParams 来设置相关的属性

    RelativeLayout 还可以通过 addRule() 方法添加规则,就是设置位置:是参考父容器呢?还是参考子控件?又或者设置 margin 等等

纯 Java 代码加载布局

平时我们都使用 XML 生成我们需要的布局,但在某些特定的情况下,则需要使用 Java 代码往我们的布局中动态的添加组件或者布局

注意: 我们不推荐大家完全地使用 Java 代码来编写 Android 页面布局,首先一点就是代码会多, 一多久容易乱,而且不利于业务的分离,我们还是建议使用 xml 来完成布局,然后通过 Java 代码对里面的组件进行修改,当然有些时候可能需要使用 Java 动态的来添加组件

使用 LayoutInflater 纯 Java 代码加载布局的流程一般如下

  1. 创建容器

    LinearLayout ly = new LinearLayout(this);
    
  2. 创建组件

    Button btnOne = new Button(this);
    
  3. 为容器或者组件设置相关属性

    比如可以设置组件 LinearLayout 的排列方向

    ly.setOrientation(LinearLayout.VERTICAL);
    

    或者设置某个控件,比如 Button

    btnOne.setText("按钮1");
    
  4. 将组件或容器添加到容器中

    我们可能需要设置下组件的添加位置,或者设置他的大小

    我们需要用到一个类:LayoutParams,可以看成布局容器的一个信息包,封装位置与大小等信息的一个类

    比如设置 LinearLayout 大小的方法

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

    很简单,接着就到这个设置位置了,设置位置的话,通常我们考虑的只是 RelativeLayout

    需要用到 LayoutParams.addRule() 方法

    如果需要设置组件在父容器中的位置,比如 设置组件的对其方式

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

    参照其它组件的对其方式

    比如设置 btnOne 居中后,让 BtnTwo 位于 btnOne 的下方以及父容器的右边

    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);  
        }  
    }
    
  5. 调用 setContentView() 方法加载布局对象即可

    如果你想移除某个容器中的 View,可以调用容器. removeView (要移除的组件);

Java 代码动态添加控件

动态添加组件的写法有两种,区别在于是否需要先调用

setContentView(R.layout.activity_main);

下面的范例演示了两种不同写法添加一个 Button

首先修改布局文件 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>

第一种方法是不需要 setContentView() 加载布局文件先

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

第二种是不需要 setContentView() 加载布局文件先

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

两种方式的代码都很简单

在创建按钮后,然后创建一个 LayoutParams 对象,用来设置 Button 的大小, 又通过 addRule() 方法设置了 Button 的位置

  1. 第一种方法,通过 LayoutInflate 的 inflate() 方法加载了 activity_main 布局,获得了外层容器,接着 addView() 添加按钮进容器,最后 setContentView();

  2. 第二种方法中,因为我们已经通过 setContetView() 方法加载了布局,所以可以直接通过 findViewById() 找到这个外层容器,接着 addView(),最后 setContentView()

注意, setContentView() 设置的视图节点是整个 XML 的根节点

使用 LayoutInflater 动态加载 XML 布局的步骤

  1. 获取容器对象

    final RelativeLayout rly = (RelativeLayout) findViewById(R.id.RelativeLayout1);
    
  2. 获得 Inflater 对象,同时加载被添加的布局的 xml,通过 findViewById 找到最外层的根节点

    final LayoutInflater inflater = LayoutInflater.from(this);
    LinearLayout ly = (LinearLayout) inflater.inflate(R.layout.inflate, null, false).findViewById(R.id.ly_inflate);
    
  3. 为这个容器设置大小与位置信息

    RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(  
           LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);  
    lp.addRule(RelativeLayout.CENTER_IN_PARENT);
    
  4. 添加到外层容器中

    rly.addView(ly,lp);
    

范例

我们写一个 demo,动态地添加 xml 文件


  1. 创建一个 空的 Android 项目 cn.twle.android.LayoutInflater

  2. 修改 activity_main.xml

    <?xml version="1.0" encoding="utf-8"?> 
    <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/btn_load"
            android:layout_marginTop="100dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="动态加载布局"/>
    
    </RelativeLayout>
    
  3. 创建一个布局文件 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>
    
  4. 修改 MainActivity.java 动态加载 xml 布局

    package cn.twle.android.layoutinflater;
    
    import android.app.Activity;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.widget.Button;
    import android.widget.LinearLayout;
    import android.widget.RelativeLayout;
    
    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.btn_load);
            btnLoad.setOnClickListener(new View.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(
                            RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
                    lp.addRule(RelativeLayout.CENTER_IN_PARENT);
                    rly.addView(ly,lp);
                }
            });
        }
    }
    

参考文档

  1. 官方 API 文档 : LayoutInflater

Android 基础教程

关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2022 简单教程 twle.cn All Rights Reserved.