ViewStub是一個輕量級View,它是一個看不見的,而且不佔佈局位置,佔用資源很是小的視圖對象。能夠爲ViewStub指定一個佈局,加載佈局時,只有ViewStub會被初始化,而後當ViewStub被設置爲可見時,或者是調用了ViewStub.inflate()時,ViewStub所指向的佈局會被加載和實例化,而後ViewStub的佈局屬性都會傳給它指向的佈局。這樣就能夠使用ViewStub來設置是否顯示某個佈局。java
<ViewStub android:inflatedId="@+id/inflatedId" android:id="@+id/viewStub" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout="@layout/layout_inflate_view_stub"/>
ViewStub
是繼承自View
,設置它的可見性,能夠經過ViewStub#setVisibility()
和ViewStub#inflate()
。
先看ViewStub#setVisibility()
方法。android
private WeakReference<View> mInflatedViewRef; public void setVisibility(int visibility) { if (mInflatedViewRef != null) { View view = mInflatedViewRef.get(); if (view != null) { view.setVisibility(visibility); } else { throw new IllegalStateException("setVisibility called on un-referenced view"); } } else { super.setVisibility(visibility); if (visibility == VISIBLE || visibility == INVISIBLE) { inflate(); } } }
初次調用該方法,mInflatedViewRef=null。所以會先走else邏輯。先經過super.setVisibility()
調用View
的setVisibility
方法,更改相關的標誌。而後不管設置的是View.VISIBLE
或者是View.INVISIBLE
都會去調用ViewStub#inflate()
方法。若是mInflatedViewRef!=null
,就是正常的設置可見性。
再看View#inflate()
方法。在xml佈局中ViewStub
節點下android:layout
引入的佈局會將ViewStub
替換掉,而且ViewStub
的寬高等屬性會被該佈局使用。佈局
public View inflate() { final ViewParent viewParent = getParent(); if (viewParent != null && viewParent instanceof ViewGroup) { if (mLayoutResource != 0) { final ViewGroup parent = (ViewGroup) viewParent; /* inflateViewNoAdd()方法被填充的佈局生成View對象。若是爲ViewStub設置了屬性inflatedId,那麼這裏的view的id會被替換成該inflatedId。 */ final View view = inflateViewNoAdd(parent); //將ViewStub替換成被填充的佈局,並使用了ViewStub的屬性。 replaceSelfWithView(view, parent); mInflatedViewRef = new WeakReference<>(view); if (mInflateListener != null) { //監聽事件須要在inflate()或者setVisibility()以前調用。 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"); } }
最後說一下id相關。this
<ViewStub android:inflatedId="@+id/inflatedId" android:id="@+id/viewStub" ... />
這裏定義了id和inflatedId。id是經過findViewById來獲取ViewStub的。inflatedId則是獲取被填充的佈局,前提是調用了ViewStub#setVisibility()或者ViewStub#inflate()方法。inflatedId
是在方法inflateViewNoAdd()
中設置給被填充的佈局的。code
使用ViewStub須要注意的地方。xml
replaceSelfWithView
看出來。所以ViewStub不適合須要按需隱藏的狀況。private void replaceSelfWithView(View view, ViewGroup parent) { final int index = parent.indexOfChild(this); //移除ViewStub parent.removeViewInLayout(this); final ViewGroup.LayoutParams layoutParams = getLayoutParams(); //添加被填充的佈局 if (layoutParams != null) { parent.addView(view, index, layoutParams); } else { parent.addView(view, index); } }
merge
標籤通常使用場景。對象