引言
相信在開發(fā)Android App的過程中秘豹,我們會常常遇到這樣的業(yè)務需求携御,需要在運行時根據(jù)數(shù)據(jù)動態(tài)決定顯示或隱藏某個View和布局。通常就是把可能用到的View先寫在布局里既绕,再初始化其可見性都設為View.GONE啄刹,然后在代碼中根據(jù)數(shù)據(jù)動態(tài)的更改它的可見性。雖然這樣的實現(xiàn)凄贩,邏輯簡單而且控制起來比較靈活誓军。但是也存在一定的缺點耗費資源,即使把View的初始可見View.GONE但是在Inflate布局的時候View仍然會被Inflate疲扎,即說仍然會創(chuàng)建對象昵时,會被實例化,會被設置屬性從而導致耗費內(nèi)存等資源椒丧。今天推薦一種新的機制——ViewStub壹甥,但要根據(jù)自己的業(yè)務需求來靈活使用。
一壶熏、ViewStub概述
ViewStub 直接繼承自View句柠,是一種不可見,0大小的可以在運行的時候再加載的View(A ViewStub is an invisible, zero-sized View that can be used to lazily inflate layout resources at runtime)棒假。僅只有在調(diào)用inflate()進行映射內(nèi)容布局之后(值得注意的是ViewStub只能inflate一次溯职,再次進行inflate的時候會報異常)或者設置為Visibility時才可見,功能上可以看成是高級的< include >標簽(一個把其它布局資源包含進某個特定的布局中帽哑,有點類似其他開發(fā)語言中的模板概念)缸榄。
二、ViewStub的特點祝拯、適用場景及注意事項
1甚带、ViewStub的一些特點
ViewStub只能被Inflate一次,inflate之后ViewStub對象就會被置為空佳头。即某個被ViewStub指定的布局被Inflate后鹰贵,就不能夠再通過ViewStub來控制它了。
ViewStub只能用來Inflate一個布局文件康嘉,而不是某個具體的View碉输,當然也可以把View寫在某個布局文件中。
2亭珍、ViewStub的適用場景及注意事項
在程序的運行期間敷钾,某個布局在被Inflate后枝哄,就不會有變化,除非重新啟動阻荒。因為ViewStub只能Inflate一次挠锥,inflate之后就不能直接使用ViewStub來控制布局。
想要控制顯示與隱藏的是一個布局文件侨赡,而非某個View蓖租。因為設置給ViewStub的只能是某個布局文件的Id,所以無法讓它來直接控制某個View羊壹。所以蓖宦,如果想要控制某個View的顯示與隱藏,抑或想要在運行時不斷的顯示與隱藏某個布局或View油猫,只能使用View的可見性來控制稠茂。
二、ViewStub的使用步驟
ViewStub支持在程序運行的過程中通過懶加載的模式inflate布局資源中情妖。只有當一個ViewStub的inflate()方法被調(diào)用或者被設為View.VISIBILITY時睬关,此時ViewStub會把設定的布局才會被創(chuàng)建對應的對象和實例化,并替換當前ViewStub的位置鲫售,顯示相應的效果共螺。雖然一開始ViewStub就存在于視圖樹中该肴,但是直到setVisibility(int)或inflate()方法被調(diào)用時才消耗資源情竹,否則是不加載控件的,因此消耗的資源小匀哄。這就是所謂的"懶加載”秦效。和< include >標簽一樣可以看成是一個“占位符“,可以看成自身是不呈現(xiàn)任何UI效果的視圖容器涎嚼,主要就是用于存放真實的布局和視圖阱州,所以除了設置必要的尺寸屬性和位置之外,通常必須設置三個重要屬性和一個回調(diào)監(jiān)聽接口:
android:id——ViewStub 自身的Id法梯,無論是否被inflate苔货,都可以通過findViewById拿到對應的ViewStub控件本身。
android:inflatedId——ViewStub設置的被映射的布局文件中的跟節(jié)點的Id立哑,inflate之后可以通過findViewById獲取到對應的被映射的布局對象夜惭。
android:layout——將要映射的布局文件名,注意和include 標簽里的區(qū)分(include標簽是layout:)
- ViewStub.OnInflateListener——當ViewStub成功映射預先設置的布局會觸發(fā)回調(diào)(Listener used to receive a notification after a ViewStub has successfully inflated its layout resource)
ViewStub的優(yōu)勢在于在某些場景中铛绰,并不一定需要把所有的內(nèi)容都展示出來诈茧,可以隱藏一些View視圖,待用戶需要展示的時候再加載到當前的Layout中捂掰,這個時候就可以用到ViewStub這個控件了敢会,這樣可以減少資源的消耗曾沈,使最初的加載速度變快。
三鸥昏、簡單使用ViewStub
1塞俱、首先建立將要被映射的布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container_erro_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@mipmap/bg_exit_dialog"
android:layout_gravity="center"
android:orientation="vertical">
<ImageView
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@mipmap/ic_erro_tips"
android:layout_marginBottom="16dp"/>
<TextView
android:id="@+id/tv_erro_tips"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#ffffff"
/>
</LinearLayout>
2、建立主布局引入ViewStub
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@mipmap/bg_activity">
<ViewStub
android:id="@+id/contentPanel"
android:inflatedId="@+id/inflatedStart"
android:layout="@layout/layout_no_data"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="showViewStub"
android:layout_alignParentBottom="true"
android:layout_marginBottom="48dp"
android:text="showViewStub"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="hideViewStub"
android:layout_alignParentBottom="true"
android:text="hideViewStub"/>
</RelativeLayout>
3互广、實現(xiàn)MainActivity
package com.crazymo.swiperefreshlayout;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.view.ViewStub;
import android.widget.LinearLayout;
import android.widget.TextView;
public class ViewStubActivity extends AppCompatActivity implements ViewStub.OnInflateListener {
private ViewStub viewStub;
private LinearLayout parentContainer;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_stub);
init();
}
private void init() {
viewStub= (ViewStub) findViewById(R.id.contentPanel);
viewStub.setOnInflateListener(this);
}
@Override
public void onInflate(ViewStub stub, View inflated) {
//inflate ViewStub的時候顯示
Log.e("ViewStub","ViewStub is loaded! viewStub==null"+(viewStub==null));
}
public void showViewStub(View view){
showViewStub();
}
private void showViewStub() {
try {
Log.e("ViewStub","ViewStub load before! viewStub==null"+(viewStub==null));
parentContainer = (LinearLayout) viewStub.inflate();
textView = (TextView) parentContainer.findViewById(R.id.tv_erro_tips);
textView.setText("不好意思敛腌,還未錄入任何數(shù)據(jù)");
}catch (Exception e){
if(parentContainer==null) {
parentContainer = (LinearLayout) findViewById(R.id.inflatedStart);
}
if(textView==null) {
textView = (TextView) parentContainer.findViewById(R.id.tv_erro_tips);
}
textView.setText("不好意思,還未錄入任何數(shù)據(jù)");
viewStub.setVisibility(View.VISIBLE);
}
}
public void hideViewStub(View view){
viewStub.setVisibility(View.GONE);
}
}
初始化和隱藏ViewStub之后MainActivity的布局層次結構
[圖片上傳失敗...(image-560006-1512722888068)]
顯示ViewStub之后
#引言
相信在開發(fā)Android App的過程中惫皱,我們會常常遇到這樣的業(yè)務需求像樊,需要在運行時根據(jù)數(shù)據(jù)動態(tài)決定顯示或隱藏某個View和布局。通常就是把可能用到的View先寫在布局里旅敷,再初始化其可見性都設為View.GONE生棍,然后在代碼中根據(jù)數(shù)據(jù)動態(tài)的更改它的可見性。雖然這樣的實現(xiàn)媳谁,邏輯簡單而且控制起來比較靈活涂滴。但是也存在一定的缺點耗費資源,即使把View的初始可見View.GONE但是在Inflate布局的時候View仍然會被Inflate晴音,即說仍然會創(chuàng)建對象柔纵,會被實例化,會被設置屬性從而導致耗費內(nèi)存等資源锤躁。今天推薦一種新的機制——ViewStub搁料,但要根據(jù)自己的業(yè)務需求來靈活使用。
一系羞、ViewStub概述
ViewStub 直接繼承自View郭计,是一種不可見,0大小的可以在運行的時候再加載的View(A ViewStub is an invisible, zero-sized View that can be used to lazily inflate layout resources at runtime)椒振。僅只有在調(diào)用inflate()進行映射內(nèi)容布局之后(值得注意的是ViewStub只能inflate一次昭伸,再次進行inflate的時候會報異常)或者設置為Visibility時才可見,功能上可以看成是高級的< include >標簽(一個把其它布局資源包含進某個特定的布局中澎迎,有點類似其他開發(fā)語言中的模板概念)庐杨。
二、ViewStub的特點夹供、適用場景及注意事項
1灵份、ViewStub的一些特點
ViewStub只能被Inflate一次,inflate之后ViewStub對象就會被置為空罩引。即某個被ViewStub指定的布局被Inflate后各吨,就不能夠再通過ViewStub來控制它了。
ViewStub只能用來Inflate一個布局文件,而不是某個具體的View揭蜒,當然也可以把View寫在某個布局文件中横浑。
2、ViewStub的適用場景及注意事項
在程序的運行期間屉更,某個布局在被Inflate后徙融,就不會有變化,除非重新啟動瑰谜。因為ViewStub只能Inflate一次欺冀,inflate之后就不能直接使用ViewStub來控制布局。
想要控制顯示與隱藏的是一個布局文件萨脑,而非某個View隐轩。因為設置給ViewStub的只能是某個布局文件的Id,所以無法讓它來直接控制某個View渤早。所以职车,如果想要控制某個View的顯示與隱藏,抑或想要在運行時不斷的顯示與隱藏某個布局或View鹊杖,只能使用View的可見性來控制悴灵。
二、ViewStub的使用步驟
ViewStub支持在程序運行的過程中通過懶加載的模式inflate布局資源中骂蓖。只有當一個ViewStub的inflate()方法被調(diào)用或者被設為View.VISIBILITY時积瞒,此時ViewStub會把設定的布局才會被創(chuàng)建對應的對象和實例化,并替換當前ViewStub的位置登下,顯示相應的效果茫孔。雖然一開始ViewStub就存在于視圖樹中,但是直到setVisibility(int)或inflate()方法被調(diào)用時才消耗資源庐船,否則是不加載控件的银酬,因此消耗的資源小嘲更。這就是所謂的"懶加載”筐钟。和< include >標簽一樣可以看成是一個“占位符“,可以看成自身是不呈現(xiàn)任何UI效果的視圖容器赋朦,主要就是用于存放真實的布局和視圖篓冲,所以除了設置必要的尺寸屬性和位置之外,通常必須設置三個重要屬性和一個回調(diào)監(jiān)聽接口:
android:id——ViewStub 自身的Id宠哄,無論是否被inflate壹将,都可以通過findViewById拿到對應的ViewStub控件本身。
android:inflatedId——ViewStub設置的被映射的布局文件中的跟節(jié)點的Id毛嫉,inflate之后可以通過findViewById獲取到對應的被映射的布局對象诽俯。
android:layout——將要映射的布局文件名,注意和include 標簽里的區(qū)分(include標簽是layout:)
- ViewStub.OnInflateListener——當ViewStub成功映射預先設置的布局會觸發(fā)回調(diào)(Listener used to receive a notification after a ViewStub has successfully inflated its layout resource)
ViewStub的優(yōu)勢在于在某些場景中承粤,并不一定需要把所有的內(nèi)容都展示出來暴区,可以隱藏一些View視圖闯团,待用戶需要展示的時候再加載到當前的Layout中,這個時候就可以用到ViewStub這個控件了仙粱,這樣可以減少資源的消耗房交,使最初的加載速度變快。
三伐割、簡單使用ViewStub
1候味、首先建立將要被映射的布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container_erro_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@mipmap/bg_exit_dialog"
android:layout_gravity="center"
android:orientation="vertical">
<ImageView
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@mipmap/ic_erro_tips"
android:layout_marginBottom="16dp"/>
<TextView
android:id="@+id/tv_erro_tips"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#ffffff"
/>
</LinearLayout>
2、建立主布局引入ViewStub
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@mipmap/bg_activity">
<ViewStub
android:id="@+id/contentPanel"
android:inflatedId="@+id/inflatedStart"
android:layout="@layout/layout_no_data"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="showViewStub"
android:layout_alignParentBottom="true"
android:layout_marginBottom="48dp"
android:text="showViewStub"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="hideViewStub"
android:layout_alignParentBottom="true"
android:text="hideViewStub"/>
</RelativeLayout>
3隔心、實現(xiàn)MainActivity
package com.crazymo.swiperefreshlayout;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.view.ViewStub;
import android.widget.LinearLayout;
import android.widget.TextView;
public class ViewStubActivity extends AppCompatActivity implements ViewStub.OnInflateListener {
private ViewStub viewStub;
private LinearLayout parentContainer;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_stub);
init();
}
private void init() {
viewStub= (ViewStub) findViewById(R.id.contentPanel);
viewStub.setOnInflateListener(this);
}
@Override
public void onInflate(ViewStub stub, View inflated) {
//inflate ViewStub的時候顯示
Log.e("ViewStub","ViewStub is loaded! viewStub==null"+(viewStub==null));
}
public void showViewStub(View view){
showViewStub();
}
private void showViewStub() {
try {
Log.e("ViewStub","ViewStub load before! viewStub==null"+(viewStub==null));
parentContainer = (LinearLayout) viewStub.inflate();
textView = (TextView) parentContainer.findViewById(R.id.tv_erro_tips);
textView.setText("不好意思白群,還未錄入任何數(shù)據(jù)");
}catch (Exception e){
if(parentContainer==null) {
parentContainer = (LinearLayout) findViewById(R.id.inflatedStart);
}
if(textView==null) {
textView = (TextView) parentContainer.findViewById(R.id.tv_erro_tips);
}
textView.setText("不好意思,還未錄入任何數(shù)據(jù)");
viewStub.setVisibility(View.VISIBLE);
}
}
public void hideViewStub(View view){
viewStub.setVisibility(View.GONE);
}
}
初始化和隱藏ViewStub之后MainActivity的布局層次結構
[圖片上傳失敗...(image-af0d98-1512723146954)]
顯示ViewStub之后