android中ViewStub惰性加載布局
我們先來看看看這個控件類吧
一、結構
public final class ViewStub extends View
java.lang.Object
android.view.View
android.view.ViewStub
二、類概述
ViewStub 是一個隐藏的,不占用記憶體空間的視圖對象,它可以在運作時延遲加載布局資源檔案。當ViewStub可見,或者調用 inflate()函數時,才會加載這個布局資源檔案。 該ViewStub在加載視圖時在父容器中替換它本身。是以,ViewStub會一直存在于視圖中,直到調用setVisibility(int) 或者inflate()為止。ViewStub的布局參數會随着加載的視圖數一同被添加到ViewStub父容器。同樣,你也可以通過使用inflatedId屬性來定義或重命名要加載的視圖對象的Id值。例如:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicGcq5SMfhTMtATMtATMwIzLcBTMvwFMxAjMvwFM0EjclZ3bvwVbvN2Xzd2bsJmbj9CXt92YuM3ZvxmYuNmLzV2Zh1Wavw1LcpDc0RHaiojIsJye.jpg)
通過"stud"id可以找到被定義的ViewStub對象。加載布局資源檔案"mySubTree "後, ViewStub對象從其父容器中移除。可以通過id"subTree"找到由布局資源"mySubTree"建立的View。這個視圖對象最後被指定為寬120dip,高40dip。執行加載布局資源檔案的推薦方式如下:
當inflate()被調用, 這個ViewStub被加載的視圖替代并且傳回這個視圖對象。這使得應用程式不需要額外執行findViewById()來擷取加載視圖的引用。
(譯者注:這個類大概意思是用ViewStub類和在XML檔案裡面指定的布局資源檔案關聯起來,讓布局資源檔案在需要使用的時候再加載上去。主要作用是性能優化,什麼時候用什麼時候加載,不用在開始啟動的時候一次加載,既可以加快程式的啟動速度,又可以節省記憶體資源。)
三、嵌套類
接口 ViewStub.OnInflateListener 一個用于接收ViewStub已經成功加載布局資源檔案的通知的監聽器。
四、XML屬性
屬性名稱 | 相關方法 | 描述 |
android:inflatedId | setInflatedId(int) | 覆寫待加載視圖的id值。 |
android:layout | setLayoutResource(int) | 為待加載的資源視圖提供一個辨別,在ViewStub變為可見或擷取焦點時使用它。(譯者注:要引用的布局資源檔案id) |
五、構造函數
ViewStub(Context context, int layoutResource)
建立一個與指定的布局資源檔案關聯的ViewStub對象。
參數
layoutResource 要加載的布局資源檔案的 id 值。
六、公共方法
public void draw (Canvas canvas)
手動在指定的畫布繪制這個視圖(及所有其子視圖)。這個視圖必須在調用這個函數之前做好了整體布局。當要自己實作一個視圖時,不要重載這個方法;相反,你應該重載onDraw(Canvas)方法。(譯者注:主要用于自定義的視圖元件的方法。)
參數
canvas 這個畫布傳到那個已渲染的視圖對象。
public int getInflatedId ()
傳回加載的布局資源檔案的ID,如果加載的布局資源檔案的id是NO_ID,那麼這個加載的View将保留它原來的id值。
相關XML 屬性
android:inflatedId
傳回值
一個正整數來辨別這個要加載的視圖或者NO_ID将保持加載視圖原來的id。
參見
setInflatedId(int)
public int getLayoutResource ()
傳回加載的布局資源檔案的id值。
相關XML 屬性
android:layout
傳回值
加載到視圖對象的布局資源檔案id值。
參見
setLayoutResource(int)
setVisibility(int)
inflate()
public View inflate ()
加載getLayoutResource()方法辨別的布局資源,并通過加載布局資源替換父容器中它自己。
傳回值
這個已加載的布局資源檔案.
public void setInflatedId (int inflatedId)
設定加載視圖的ID。如果這個id為NO_ID,這個加載視圖保持它原來的id不變。
相關XML 屬性
android:inflatedId
參數
inflatedId 一個正整數來辨別這個加載視圖或者NO_ID将保持加載視圖原來的id。
參見
getInflatedId()
public void setLayoutResource (int layoutResource)
設定待加載的布局資源檔案,當ViewStub被設定為visible或invisible或調用inflate()時使用。這個在加載布局資源檔案時建立的視圖用來在父容器中替換它自己。
相關XML 屬性
android:layout
參數
layoutResource 一個有效的布局資源檔案id值(不等于0)。
參見
getLayoutResource()
setVisibility(int)
inflate()
public void setOnInflateListener (ViewStub.OnInflateListener inflateListener)
設定成功加載布局資源檔案後事件通知的監聽器。
參數
inflateListener 該OnInflateListener在成功加載後得到事件通知。
參見
ViewStub.OnInflateListener
public void setVisibility (int visibility)
當可見性設定為VISIBLE或INVISIBLE,inflate()将被調用,并且加載視圖資源在父容器中替換ViewStub。
參數
visibility 設定為VISIBLE(顯示), INVISIBLE(隐藏), 或 GONE(完全隐藏,不暫用布局位置).
參見
inflate()
七、受保護方法
protected void dispatchDraw (Canvas canvas)
調用這個函數去繪制這個控件的子視圖。可以通過派生類重寫在繪制子類之前擷取控制(但是是在他自己的視圖已經被繪制完之後)
參數
canvas 這個畫布傳到那個已渲染的視圖對象。
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec)
測量這個視圖以确定其内容的高度和寬度。通過measure(int, int)來調用這個方法,并且應該由子類重寫以提高内容測量的效率和精确度。
約定:當該方法被重寫時,你必須調用setMeasuredDimension(int, int)來存儲已測量視圖的高度和寬度。否則将通過measure(int, int)抛出一個IllegalStateException異常。調用父類的onMeasure(int, int)方法是一個有效的辦法。
父類的實作是以背景大小為預設大小,除非MeasureSpec(測量細則)允許更大的背景。為了更好測量内容子類應該重寫onMeasure(int, int)。
如果這個方法被重寫,子類有責任確定測量它的高度和寬度至少是視圖的最小寬度和高度(getSuggestedMinimumHeight()和getSuggestedMinimumWidth())。
參數
widthMeasureSpec 由于父類有橫向空間要求,參見View.MeasureSpec。
heightMeasureSpec 由于父類有縱向空間要求,參見 View.MeasureSpec 。
然後,為了便于了解,小白特簡單的測試了一下,直接上代碼-------此處順便測試一下include(也可以反複引用布局檔案)
1、先定義一個布局檔案,作為引用的布局檔案---檔案名為 next_layout
<?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:orientation="vertical" >
<RatingBar
android:id="@+id/rb"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
2、然後繪制主布局,即activity中聲明加載的,即setcontentView
<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"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<!-- 使用include引用布局檔案 -->
<include
android:layout_width="fill_parent"
android:layout_height="wrap_content"
layout="@layout/next_layout" />
<!-- 使用ViewStub引用布局檔案 -->
<ViewStub
android:id="@+id/stub"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout="@layout/next_layout" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#00ffff"
android:text="動态加載布局" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:background="#ffff00"
android:text="動态隐藏布局" />
</LinearLayout>
</LinearLayout>
3、在activity中測試,源碼為
package com.example.viewstub;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewStub;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.RatingBar;
public class MainActivity extends Activity {
private Button button1, button2;
private ViewStub stub;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 初始化控件
button1 = (Button) findViewById(R.id.button1);
button2 = (Button) findViewById(R.id.button2);
stub = (ViewStub) findViewById(R.id.stub);
// 為button1設定監聽事件
button1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
// ViesStub控件隻能獲得一次,第二次再使用findViewById獲得該ViewStub對象,則傳回null
View v1 = stub.inflate();// 調用此方法,加載布局。當然也可以通過setVisibility方法
RatingBar rb = (RatingBar) v1.findViewById(R.id.rb);// 從動态加載的布局中獲得相應控件
rb.setNumStars(3);// 設定已獲得控件的屬性
}
});
// 為button2設定監聽事件
button2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
stub.setVisibility(View.GONE);
// 值得注意的是,若使用下面的屬性值,除了占用布局空間外,而且,若是你直接點選此按鈕(沒有加載布局之前),則他會先自動加載布局,然後當你再次點選時,才會隐藏的。
// 這一點應該引起注意。是以 選用 View.GONE 效果更好,推薦使用。
// stub.setVisibility(View.INVISIBLE);
}
});
}
}
效果圖: 進入應用的效果1
點選動态加載布局後的效果
點選隐藏布局 後效果
再一次點選動态加載布局時效果
最後,歡迎交流,本人小白 QQ 964079433