欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android技巧之ViewStub的使用

程序员文章站 2022-03-20 13:10:02
...

小提示:使用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的情况
Android技巧之ViewStub的使用

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的情况
Android技巧之ViewStub的使用

此处将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标签为根标签的布局文件时不能正常加载,会报如下错误:
Android技巧之ViewStub的使用