基于 6.0.1_r10
作用
ViewStub 可以用來優(yōu)化布局,實(shí)現(xiàn)布局的懶加載。
ViewStub 不占用屏幕空間,大小為0
只有當(dāng)調(diào)用 inflate 或者 viewStub.setVisibility(View.VISIBLE||INVISIBLE) 時(shí)才會(huì)加載布局
構(gòu)造方法
ViewStub 5 個(gè)構(gòu)造方法,層層包裹,最終會(huì)調(diào)用下面方法
public ViewStub(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context);
final TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.ViewStub, defStyleAttr, defStyleRes);
mInflatedId = a.getResourceId(R.styleable.ViewStub_inflatedId, NO_ID);
mLayoutResource = a.getResourceId(R.styleable.ViewStub_layout, 0);
mID = a.getResourceId(R.styleable.ViewStub_id, NO_ID);
a.recycle();
setVisibility(GONE);
setWillNotDraw(true);
}
可以看出 ViewStub 構(gòu)造方法
1. 組件本身 setVisibility(GONE)
2. setWillNotDraw(true);
所以 ViewStub 不會(huì)繪制出來,不占用屏幕空間。
ViewStub 使用
-
setVisibility()
ViewStub 重載了 View 的 setVisibility() 方法@Override @android.view.RemotableViewMethod 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(); } } }
-
直接調(diào)用 inflate()
public View inflate() { final ViewParent viewParent = getParent(); if (viewParent != null && viewParent instanceof ViewGroup) { if (mLayoutResource != 0) { final ViewGroup parent = (ViewGroup) viewParent; final LayoutInflater factory; if (mInflater != null) { factory = mInflater; } else { factory = LayoutInflater.from(mContext); } final View view = factory.inflate(mLayoutResource, parent, false); if (mInflatedId != NO_ID) { view.setId(mInflatedId); } 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); } mInflatedViewRef = new WeakReference<View>(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"); } }
分析以上代碼
1. ViewStub 必須有一個(gè)父控件
2. setVisibility 顯示布局的時(shí)候,會(huì)調(diào)用 inflate
3. inflate 只能調(diào)用一次,會(huì)把加載到的 View 放到弱引用 mInflatedViewRef 中
兩次調(diào)用 inflate ,會(huì)因?yàn)榈谝淮伟?ViewStub 從 parentView 中移除,導(dǎo)致出現(xiàn) crash
4. inflate 調(diào)用時(shí)會(huì)用真正的布局,替換 ViewStub (加載到父布局同樣的位置)
5. inflate 調(diào)用以后,setVisibility 使用 mInflatedViewRef 控制布局顯示/隱藏
以上就是 ViewStub 的全部,代碼比較簡單注釋也比較全面。
總結(jié)一個(gè)簡單的流程圖如下
viewStub_01.png
ViewStub 用到 LayoutInflater 加載布局文件,LayoutInflater 的用法可以參考LayoutInflater 源碼閱讀筆記