Android:ViewStub

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()调用ViewsetVisibility方法,更改相关的标志。而后不管设置的是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

  • ViewStub只能加载一次。这个能够从方法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);
        }
    }
  • ViewStub不能嵌套merge标签

通常使用场景。对象

  • 程序运行期间,某个布局在加载后,就不会有变化,除非销毁该页面再从新加载。
  • 想要控制显示与隐藏的是一个布局文件,而非某个view。
相关文章
相关标签/搜索
本站公众号
   欢迎关注本站公众号,获取更多信息