ViewStub 源碼學(xué)習(xí)

基于 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 使用

  1. 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();
             }
         }
     }
    
  2. 直接調(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 源碼閱讀筆記

參考資料

developer 官方文檔

ViewStub 源碼

LayoutInflater 源碼閱讀筆記

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 引言:一個(gè)可用于性能優(yōu)化的控件。時(shí)間:2017年09月21日作者:JustDo23Github:https://g...
    JustDo23閱讀 6,321評論 4 5
  • 學(xué)習(xí)過程中遇到什么問題或者想獲取學(xué)習(xí)資源的話,歡迎加入Android學(xué)習(xí)交流群,群號碼:364595326 我們一...
    kingZXY2009閱讀 351評論 0 0
  • Viewtub源碼分析 A ViewStub is an invisible, zero-sized View t...
    Y小圓臉閱讀 348評論 0 0
  • ¥開啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個(gè)線程,因...
    小菜c閱讀 6,537評論 0 17
  • 1、啟動(dòng)白屏、黑屏 給啟動(dòng)頁設(shè)置Theme,看起來就像秒啟動(dòng)了。 一般啟動(dòng)頁也就一張圖片,直接設(shè)置了android...
    zsgnaw閱讀 549評論 0 1