Android技巧之ViewStub的使用

小提示:使用AndroidStudio3.1.2版查看View树
最顶部菜单栏Tools –> Layout Inspector,在弹出的窗口选择设备单击“OK”即可。

一、使用include加载布局

MainActivity的布局文件如下所示:

<?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:gravity="center"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <!--填充布局,不带merge-->
    <include
        android:id="@+id/hear_include_1"
        layout="@layout/hear_1_layout" />

</LinearLayout>
1.1 未使用merge的情况

hear_1_layout.xml的源码如下所示:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#f00">

    <TextView
        android:id="@+id/tv_1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:gravity="center"
        android:padding="5dp"
        android:text="头标题1"
        android:textColor="@android:color/black"
        android:textSize="24sp" />
</FrameLayout>
1.2 使用merge的情况

此处将MainActivity布局文件中include标签的属性layout的值改为hear_2_layout
hear_2_layout.xml的源码如下所示:

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#0f0"
    >

    <TextView
        android:id="@+id/tv_2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:padding="5dp"
        android:text="头标题2"
        android:textColor="@android:color/black"
        android:textSize="24sp" />
</merge>

结论:

(1) 未使用merge时:include标签加载布局的时候,其所加载的布局根View所有的属性参数都是有效的

(2) 使用merge时:include标签加载布局的时候,实质就是将merge中的子View添加至include标签的父View下,所以merge标签的布局属性是无效的

二、使用ViewStub

MainActivity的布局文件如下所示:

<?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:gravity="center"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center"
            android:orientation="vertical">

            <!--填充布局,不带merge-->
            <include
                android:id="@+id/hear_include_1"
                layout="@layout/hear_1_layout" />

            <!--填充布局,带merge-->
            <include
                android:id="@+id/hear_include_2"
                layout="@layout/hear_2_layout" />

            <TextView
                android:id="@+id/tv"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="#00f"
                android:text="Hello World!"
                android:textColor="@android:color/black"
                android:textSize="24sp" />

            <!--
            填充布局,不带merge。inflateId指定的id是layout中
            所加载布局的根View的Id。
            注意:不管layout中所加载的布局的根View是否添加过id,
            inflateId所指定的id都是layout所加载布局的根View的id
            -->
            <ViewStub
                android:id="@+id/vs_1"
                android:layout_width="match_parent"
                android:layout_height="150dp"
                android:background="#ff0"
                android:inflatedId="@+id/vs_hear_1"
                android:layout="@layout/hear_1_layout" />

            <!--填充布局,带merge。这样使用将会报错-->
            <!--<ViewStub
                android:id="@+id/vs_2"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="#ff0"
                android:inflatedId="@+id/vs_hear_2"
                android:layout="@layout/hear_2_layout" />-->

        </LinearLayout>
    </ScrollView>
</LinearLayout>

MainActivity.java的源码如下所示:

package org.chromium.chrome.browser.viewstubdemo;

import android.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewStub;
import android.widget.LinearLayout;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    private ViewStub vs1;
    private String TAG = "MainActivity_layout";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView tv = (TextView) findViewById(R.id.tv);
        vs1 = (ViewStub) findViewById(R.id.vs_1);

        tv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //vs1.inflate();此方法只能执行一次,第二次执行就会报错
                //报错如下:java.lang.IllegalStateException:
                // ViewStub must have a non-null ViewGroup viewParent
                //vs1.inflate();
                vs1.setVisibility(View.VISIBLE);
                View fl_1 = MainActivity.this.findViewById(R.id.fl);
                //layout is null
                Log.e(TAG, "layout is " + fl_1);
                View fl_2 = MainActivity.this.findViewById(R.id.vs_hear_1);
                //layout is android.widget.FrameLayout{5aa6820 V.E...... ......ID 0,0-0,0 #7f070096 app:id/vs_hear_1}
                Log.e(TAG, "layout is " + fl_2);

                //layout is wrap_content
                int height = fl_2.getLayoutParams().height;
                if (height== ViewGroup.LayoutParams.WRAP_CONTENT) {
                    Log.e(TAG, "layout is wrap_content");
                } else if (height == ViewGroup.LayoutParams.MATCH_PARENT) {
                    Log.e(TAG, "layout is match_parent");
                } else {
                    Log.e(TAG, "layout is " + height);
                }
            }
        });

    }
}

结论:

(1) 当ViewStub的layout属性使用非merge标签为根标签的布局文件时能够正常加载

(2) 当ViewStub的layout属性使用merge标签为根标签的布局文件时不能正常加载,会报如下错误:
这里写图片描述

猜你喜欢

转载自blog.csdn.net/Duckdan/article/details/81207296
今日推荐