Android之ViewStub的简单使用
1.viewstub就是動(dòng)態(tài)加載試圖;也就是在我們的app啟動(dòng)繪制頁(yè)面的時(shí)候,他不會(huì)繪制到view樹中;當(dāng)在代碼中執(zhí)行inflate操作后,她才會(huì)被添加到試圖中。其實(shí)ViewStub就是一個(gè)寬高都為0的一個(gè)View,它默認(rèn)是不可見的,只有通過(guò)調(diào)用setVisibility函數(shù)或者Inflate函數(shù)才 會(huì)將其要裝載的目標(biāo)布局給加載出來(lái),從而達(dá)到延遲加載的效果,這個(gè)要被加載的布局通過(guò)android:layout屬性來(lái)設(shè)置。最終目的是把a(bǔ)pp加載頁(yè)面的速度提高了,使用戶體驗(yàn)更好。
2.看一個(gè)簡(jiǎn)單的demo
viewstub.xml
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:id="@+id/inflatedStart"android:layout_width="match_parent"android:layout_height="match_parent"><TextViewandroid:id="@+id/hello_tv"android:layout_width="wrap_content"android:layout_height="wrap_content"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent"android:text="DATA EMPTY!"/></android.support.constraint.ConstraintLayout> activity_myviewstub.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:onClick="inflate"android:text="inflate" /><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:onClick="setData"android:text="setdata"/><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:onClick="hide"android:text="hide"/><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:onClick="show"android:text="show"/><ViewStubandroid:id="@+id/vs"android:inflatedId="@+id/inflatedStart"android:layout="@layout/viewstub"android:layout_width="match_parent"android:layout_height="match_parent" /></LinearLayout> MyViewStubActivity.java package com.ysl.myandroidbase.viewstub;import android.os.Bundle; import android.support.annotation.Nullable; import android.support.constraint.ConstraintLayout; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.view.ViewStub; import android.widget.TextView;import com.ysl.myandroidbase.R;public class MyViewStubActivity extends AppCompatActivity {private ViewStub viewStub;private TextView textView;private View inflate;private ConstraintLayout constraintLayout;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_myviewstub);viewStub = findViewById(R.id.vs);//textView = (TextView) findViewById(R.id.hello_tv);空指針,因?yàn)関iewstub沒有inflate}public void inflate(View view){if (inflate == null) {//inflate只會(huì)進(jìn)行一次,當(dāng)?shù)诙握{(diào)用的時(shí)候,就會(huì)拋異常;也可以try catch進(jìn)行處理inflate = viewStub.inflate();constraintLayout = findViewById(R.id.inflatedStart);System.out.println(constraintLayout);System.out.println("viewStub-------->"+viewStub);textView = viewStub.findViewById(R.id.hello_tv);//獲取到的textview是空的;System.out.println("viewStub textView-------->"+textView);//nulltextView = constraintLayout.findViewById(R.id.hello_tv);System.out.println("constraintLayout textView-------->"+textView);textView = findViewById(R.id.hello_tv);System.out.println("textView-------->"+textView);}}public void setData(View view){if (constraintLayout != null) {textView = constraintLayout.findViewById(R.id.hello_tv);textView.setText("HAVE DATA !!!");}}public void hide(View view){viewStub.setVisibility(View.GONE); // if (constraintLayout != null){ // constraintLayout.setVisibility(View.GONE); // }}public void show(View view){viewStub.setVisibility(View.VISIBLE); // if (constraintLayout != null){ // constraintLayout.setVisibility(View.VISIBLE); // }} }3.當(dāng)調(diào)用第二次inflate的時(shí)候,會(huì)報(bào)錯(cuò):
我們看一下這是為什么?進(jìn)入viewStub.inflate();的源碼:
public View inflate() {final ViewParent viewParent = getParent();if (viewParent != null && viewParent instanceof ViewGroup) {if (mLayoutResource != 0) {final ViewGroup parent = (ViewGroup) viewParent;final View view = inflateViewNoAdd(parent);replaceSelfWithView(view, parent);mInflatedViewRef = new WeakReference<>(view);if (mInflateListener != null) {mInflateListener.onInflate(this, view);}return view;} else {throw new IllegalArgumentException("ViewStub must have a valid layoutResource");}} else {throw new IllegalStateException("ViewStub must have a non-null ViewGroup viewParent");}}可以看到當(dāng)viewParent為空或者不是viewgroup時(shí)才會(huì)報(bào)這個(gè)錯(cuò)誤;那么第一次調(diào)用的時(shí)候,肯定是進(jìn)去了;發(fā)現(xiàn)一個(gè)方法replaceSelfWithView(view,parent);view就是我們?cè)诓季治募薪oviewstub指定的layout所引用的那個(gè)布局;parent就是getParent方法得到的,也就是acticity的填充布局LinearLayout;
進(jìn)去看一下:
private void replaceSelfWithView(View view, ViewGroup parent) {final int index = parent.indexOfChild(this);parent.removeViewInLayout(this);final ViewGroup.LayoutParams layoutParams = getLayoutParams();if (layoutParams != null) {parent.addView(view, index, layoutParams);} else {parent.addView(view, index);}}可以發(fā)現(xiàn)parent.removeViewInLayout(this);把this就是viewstub從父布局linearlayout中移除了;parent.addView()就是把view(也就是我們引用的布局)添加到了父布局LinearLayout中。
我們用layout inspector來(lái)查看一下:
inflate前:可以看到viewstub是灰色的
inflate后:可以看到viewstub直接被移除了,把引用布局直接放到view樹里了。
所以當(dāng)我們第二次再調(diào)用inflate方法時(shí),viewstub的parent已經(jīng)為空了;就會(huì)拋出此異常;
當(dāng)調(diào)用textView = viewStub.findViewById(R.id.hello_tv);//獲取到的textview是空的;
而使用textView = findViewById(R.id.hello_tv);就可以直接拿到控件對(duì)象了;
當(dāng)實(shí)現(xiàn)引用布局的顯示和隱藏時(shí),測(cè)試發(fā)現(xiàn)使用viewstub的setVisibility()方法可以實(shí)現(xiàn),這是為什么呢?;按理說(shuō)使用constraintLayout.setVisibility()當(dāng)然也可以;根據(jù)上面的view樹結(jié)構(gòu)來(lái)看,好像使用引用布局的setVisibility()方法更合理一些;
下面我們?cè)賮?lái)看看viewstub的setVisibility()為什么也可以;跟進(jìn)源碼看看:
源碼中使用mInflatedViewRef獲取到view,然后設(shè)置隱藏與顯示;mInflatedViewRef是一個(gè)view的弱引用WeakReference<View>
其實(shí)在上面的inflate方法中已經(jīng)為其添加了mInflatedViewRef = new WeakReference<>(view);這個(gè)view就是viewstub中的引用布局;
所以,使用viewstub可以實(shí)現(xiàn)相同的顯示或隱藏效果;
從上圖的最后一個(gè)紅色框中可以發(fā)現(xiàn),假設(shè)現(xiàn)在我沒有調(diào)用inflate方法,而是直接點(diǎn)擊了show按鈕;然后引用布局也可以繪制出來(lái);這就是我在寫demo的時(shí)候,直接上去點(diǎn)擊show按鈕,竟然也可以顯示的原因。
?
?
總結(jié)
以上是生活随笔為你收集整理的Android之ViewStub的简单使用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 软件测试前景和发展方向
- 下一篇: System Verilog Asser