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
标签通常使用场景。对象