ViewStub的初步瞭解與merge和include的使用

<include>標籤可以允許在一個佈局當中引入另外一個佈局,那麼比如說我們程序的所有界面都有一個公共的部分,這個時候最好的做法就是將這個公共的部分提取到一個獨立的佈局文件當中,然後在每個界面的佈局文件當中來引用這個公共的佈局。

<merge>標籤是作爲<include>標籤的一種輔助擴展來使用的,它的主要作用是爲了防止在引用佈局文件時產生多餘的佈局嵌套。大家都知道,Android去解析和展示一個佈局是需要消耗時間的,佈局嵌套的越多,那麼解析起來就越耗時,性能也就越差,因此我們在編寫佈局文件時應該讓嵌套的層數越少越好。

例如:

activity_main.xml

<span style="font-size:14px;"><?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:orientation="vertical" >  
    <Button  
        android:id="@+id/ok"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:text="OK" />  
    <include layout="@layout/more_layout"/>
</LinearLayout>  </span>
<span style="font-size:14px;">more_layout.xml</span>


<span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <EditText
        android:id="@+id/editText1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <EditText
        android:id="@+id/editText2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <EditText
        android:id="@+id/editText3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout></span>

activity_main.xml中最外層的LinearLayout當中包含了兩個元素,一個是Button,另一個又是一個LinearLayout,然後在這個內部的LinearLayout當中才包含了3個EditText。這個內部的LinearLayout就是一個多餘的佈局嵌套,實際上並不需要這樣一層,讓3個EditText直接包含在外部的LinearLayout當中就可以了。而這個多餘的佈局嵌套其實就是由於佈局引入所導致的,因爲我們在more_layout.xml中也定義了一個LinearLayout。

more_layout.xml應修改爲

<span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
    <EditText
        android:id="@+id/editText1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <EditText
        android:id="@+id/editText2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <EditText
        android:id="@+id/editText3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</merge></span>
換用了<merge>標籤,這就表示當有任何一個地方去include這個佈局時,會將<merge>標籤內包含的內容直接填充到include的位置,不會再添加任何額外的佈局結構。

僅在需要時才加載佈局

那麼我們如何才能讓這些不常用的元素僅在需要時纔去加載呢?Android爲此提供了一種非常輕量級的控件,ViewStub。ViewStub雖說也是View的一種,但是它沒有大小,沒有繪製功能,也不參與佈局,資源消耗非常低,將它放置在佈局當中基本可以認爲是完全不會影響性能的。

佈局文件inflate時,ViewStub主要是作爲一個“佔位符”的性質,放置於view tree中,且ViewStub本身是不可見的。ViewStub中有一個layout屬性,指向ViewStub本身可能被替換掉的佈局文件,在一定時機時,通過viewStub.inflate()完成此過程;

ViewStub本身是不可見的,對ViewStub setVisibility(..)與其他控件不一樣,ViewStub的setVisibility 成View.VISIBLE或INVISIBLE如果是首次使用,都會自動inflate其指向的佈局文件,並替換ViewStub本身,再次使用則是相當於對其指向的佈局文件設置可見性。

ViewStub之所以常稱之爲“延遲化加載”,是因爲在教多數情況下,程序無需顯示ViewStub所指向的佈局文件,只有在特定的某些較少條件下,此時ViewStub所指向的佈局文件才需要被inflate,且此佈局文件直接將當前ViewStub替換掉,具體是通過viewStub.infalte()或viewStub.setVisibility(View.VISIBLE)來完成

activity_main.xml

<span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.example.qdq.myapplication.MainActivity">

    <EditText
        android:id="@+id/editText1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />
    <Button
        android:id="@+id/more"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="更多"/>
    <ViewStub
        android:id="@+id/viewStub"
        android:layout="@layout/more_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>
</span>
注意,雖然ViewStub是不佔用任何空間的,但是每個佈局都必須要指定layout_width和layout_height屬性,否則運行就會報錯。
MainActivity中代碼

<span style="font-size:14px;">package com.example.qdq.myapplication;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewStub;
import android.widget.Button;
import android.widget.EditText;

public class MainActivity extends AppCompatActivity {
    private Button moreBt;
    private EditText editText1;
    private EditText editText2;
    private EditText editText3;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        moreBt= (Button) findViewById(R.id.more);
        moreBt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ViewStub viewStub= (ViewStub) findViewById(R.id.viewStub);
                if(viewStub!=null){
                    View view=viewStub.inflate();
                    editText1= (EditText) view.findViewById(R.id.editText1);
                    editText2= (EditText) view.findViewById(R.id.editText2);
                    editText3= (EditText) view.findViewById(R.id.editText3);
                }
            }
        });
    }
}
</span>
當點擊更多按鈕之後,我們首先會調用findViewById()方法將ViewStub的實例獲取到,拿到ViewStub的實例之後就很簡單了,調用inflate()方法或者setVisibility(View.VISIBLE)都可以將隱藏的佈局給加載出來,而加載的這個佈局就是剛纔在XML當中配置的more_layout佈局。調用inflate()方法之後會將加載出來的佈局進行返回,之後我們就可以對這個佈局進行任意的操作了,再次隱藏顯示,或者獲取子元素的實例等。注意這裏我對ViewStub的實例進行了一個非空判斷,這是因爲ViewStub在XML中定義的id只在一開始有效,一旦ViewStub中指定的佈局加載之後,這個id也就失敗了,那麼此時findViewById()得到的值也會是空。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章