美文网首页
ViewStub源码分析

ViewStub源码分析

作者: Y小圆脸 | 来源:发表于2017-07-20 17:58 被阅读41次

Viewtub源码分析

A ViewStub is an invisible, zero-sized View that can be used to lazily inflate

ViewStub是一个不可见的0大小的视图,可以在运行时懒加载资源

When a ViewStub is made visible, or when is invoked, the layout resource is inflated. The ViewStub then replaces itself in its parent with the inflated View or Views.Therefore, the ViewStub exists in the view hierarchy until or is invoked.

当ViewStub可视化或调用时,布局资源会被加载。ViewStub加载view到父视图中。因此ViewStub存在于视图层次结构中,直到或被调用。

    <ViewStub android:id="@+id/stub"
    android:inflatedId="@+id/subTree"
    android:layout="@layout/mySubTree"
    android:layout_width="120dip"
    android:layout_height="40dip"/>

ViewStub构造方法

 public ViewStub(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context);
    
    final TypedArray a = context.obtainStyledAttributes(attrs,
            R.styleable.ViewStub, defStyleAttr, defStyleRes);
    //要被加载的布局id
    mInflatedId = a.getResourceId(R.styleable.ViewStub_inflatedId, NO_ID);
    //要被加载的布局
    mLayoutResource = a.getResourceId(R.styleable.ViewStub_layout, 0);
    // ViewStub 的 Id
    mID = a.getResourceId(R.styleable.ViewStub_id, NO_ID);
    a.recycle();

    setVisibility(GONE);
    setWillNotDraw(true);
}

核心:复写setVisibility()方法

 public void setVisibility(int visibility) {
    // mInflatedViewRef 是对布局的弱引用
    if (mInflatedViewRef != null) {
        // 如果不为 null,就拿到懒加载的 View
        View view = mInflatedViewRef.get();
        if (view != null) {
            // 然后就直接对 View 进行 setVisibility 操作
            view.setVisibility(visibility);
        } else {
            throw new IllegalStateException("setVisibility called on un-referenced view");
        }
    } else {
        super.setVisibility(visibility);
        // 之前说过,setVisibility(int) 也可以进行加载布局
        if (visibility == VISIBLE || visibility == INVISIBLE) {
            // 因为在这里调用了 inflate()
            inflate();
        }
    }
}

inflate()关键加载方法

  • 获取父视图,如果没有指定布局,就会抛出异常

  • 获取加载的布局view,并设置view的布局id

  • 计算出 ViewStub 在 parent 中的位置,先将Viewstub移除,并将view加载到布局中

  • 将View进行弱引用

     public View inflate() {
         // 获取父视图
         final ViewParent viewParent = getParent();
         // 如果没有指定布局,就会抛出异常
         if (viewParent != null && viewParent instanceof ViewGroup) {
             if (mLayoutResource != 0) {
                 // viewParent 需为 ViewGroup
                 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);
                 // 为 view 设置 Id
                 if (mInflatedId != NO_ID) {
                     view.setId(mInflatedId);
                 }
                 // 计算出 ViewStub 在 parent 中的位置
                 final int index = parent.indexOfChild(this);
                 // 把 ViewStub 从 parent 中移除
                 parent.removeViewInLayout(this);
                 // 接下来就是把 view 加到 parent 的 index 位置中
                 final ViewGroup.LayoutParams layoutParams = getLayoutParams();
                 if (layoutParams != null) {
                     // 如果 ViewStub 的 layoutParams 不为空
                     // 就设置给 view
                     parent.addView(view, index, layoutParams);
                 } else {
                     parent.addView(view, index);
                 }
                 // mInflatedViewRef 就是在这里对 view 进行了弱引用
                 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");
         }
     }
    

ViewStub相关使用

1、特点

  • ViewStub只能Inflate一次,之后ViewStub对象会被置为空。按句话说,某个被ViewStub指定的布局被Inflate后,就不会够再通过ViewStub来控制它了
  • ViewStub layout布局不能使用merge引入

在xml使用ViewStub,使用layout引入布局文件,inflatedId是引入布局文件之后的id

<ViewStub
    android:id="@+id/stub_import"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom"
    android:inflatedId="@+id/panel_import"
    android:layout="@layout/progress_overlay" />

通过java代码中的一系列判断可得出相关ViewStub特点

 @Override
public void onClick(View v) {

            //ViewStub只能Inflate一次,之后ViewStub对象会被置为空。按句话说,某个被ViewStub指定的布局被Inflate后,就不会够再通过ViewStub来控制它了
            if (mStubImport.getParent()!=null) {
                View view = mStubImport.inflate();
                if (view != null) {
                    if (view.getId() == R.id.panel_import) {
                        Log.e(TAG, "layout root id is act_layout_viewstub_new");
                    } else if (view.getId() == R.id.layout_viewstub_old) {
                        Log.e(TAG, "layout root id is layout_viewstub_old");
                    } else {
                        Log.e(TAG, "layout root id is anyone : " + view.getId());
                    }
                    // layoutView的root view布局 和mViewStub的布局保持一致
                    int width = view.getLayoutParams().width;
                    if (width == ViewGroup.LayoutParams.MATCH_PARENT) {
                        Log.e(TAG, "layout width is MATCH_PARENT");
                    } else if (width == ViewGroup.LayoutParams.WRAP_CONTENT) {
                        Log.e(TAG, "layout width is WRAP_CONTENT");
                    } else {
                        Log.e(TAG, "layout width is anyone : " + width);
                    }

                }
            } else {
                Log.e(TAG, "viewStub is inflated");
            }

}

github地址

相关文章

  • ViewStub源码分析

    Viewtub源码分析 A ViewStub is an invisible, zero-sized View t...

  • ViewStub源码分析

    辛辛苦苦写了一篇博客,发现简书markdown插入代码居然没有行序,我都懵逼了。看来这个编辑器对程序猿不太友好啊,...

  • Android源码分析(ViewStub源码解析)

    源码基于安卓8.0分析结果 ViewStub是一种不可见的并且大小为0的试图,它可以延迟到运行时才填充inflat...

  • ViewStub的使用和源码分析

    ViewStub的使用 xml文件 可以看到,ViewStub必须添加layout,这个是它需要展示的东西。inf...

  • Android 简单解读了ViewStub的代码和注释,其他的不

    ViewStub应用的场景比较少,以前用过几次。时间一长又忘记了,很是苦恼。 于是把ViewStub的源码过了一遍...

  • ViewStub 源码学习

    基于 6.0.1_r10 作用 ViewStub 可以用来优化布局,实现布局的懒加载。 ViewStub 不占用屏...

  • ViewStub源码解析

    闲来无事,把ViewStub源码看了一遍,之前只是知道大概原理,从来没有把源码仔细看过,代码很少一会就能看完,只有...

  • Android ViewStub重复加载问题(ViewStub

    错误信息 原因(重复加载ViewStub),以下为 inflate( ) 方法的源码 源码很简单,抛出异常在最后一...

  • ViewStub源码简解

    ViewStub ViewStub是一个未加载时不可见的不会占据实际大小的,且可以用来懒加载布局资源的控件。当Vi...

  • Android中ViewStub原理解析

    本文主要从如下几点来学习ViewStub ViewStub是啥 ViewStub的属性解析 ViewStub的代码...

网友评论

      本文标题:ViewStub源码分析

      本文链接:https://www.haomeiwen.com/subject/oqsjkxtx.html