通过源码学习源码我们可以看到;
ViewStub 的构造函数,
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是默认不显示的
ViewStub支持在程序运行的过程中通过懒加载的模式inflate布局资源中。只有当一个ViewStub的inflate()方法被调用或者被设为View.VISIBILITY时,此时ViewStub会把设定的布局才会被创建对应的对象和实例化,并替换当前ViewStub的位置,显示相应的效果.
那我们先来看看setVisibility(int Visibility)这个方法
@Override
@android.view.RemotableViewMethod(asyncImpl = "setVisibilityAsync")
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();
}
}
}
这个判断如果没有存在View 的情况下最终还是会走inflate()方法,那我们再看一下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");
}
}
通过代码我们可以了解到ViewStub 最终会替换成为在xml文件里面配置的layout引用的布局,并且把id替换为inflatedId.
关于ViewStub 的使用实例:
<!-- layout_viewstub.xml 要延迟加载的view -->
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:id="@+id/layout_viewstub_old"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/hello_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:background="@android:color/darker_gray"
android:padding="5dp"
android:text="This is the layout instead of ViewStub view."/>
</LinearLayout>
<!-- act_test_viewstub.xml -->
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">
<TextView
android:id="@+id/act_test_viewstub_tv_show"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:background="@android:color/darker_gray"
android:padding="5dp"
android:text="Show ViewStub"/>
<ViewStub
android:id="@+id/act_test_viewstub_viewstub"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inflatedId="@+id/act_layout_viewstub_new"
android:layout="@layout/layout_viewstub"/>
<!--<include-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="wrap_content"-->
<!--layout="@layout/layout_viewstub"/>-->
</LinearLayout>
public class ViewStubTestActivity extends FragmentActivity {
private static final String TAG = "test_viewstub";
protected ViewStub mViewStub;
private TextView textview;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.act_test_viewstub);
mViewStub = (ViewStub) findViewById(R.id.act_test_viewstub_viewstub);
textview = (TextView) findViewById(R.id.hello_tv);
textview.setText("1234556");
}
}
补充:
1.ViewStub inflate()方法只能调用一次
2.VIewStub 的布局中不要有<merge>
3.removeViewInLayout()这个和removeView 的区别是 removeView会调用requestLayout 会触发onLayout()而removeViewInLayout()方法一般在onLayout()方法里面调用没有requestLayout()更加安全
4.setWillNotDraw(false);这个方法源码注释的意思:
如果此视图本身不执行任何绘制,请设置此标志以允许进一步优化。默认情况下,此标志未在View上设置,但可以在某些View子类(如ViewGroup)上设置。通常,如果重写onDraw(Canvas),则应清除此标志。
所以使用的时候在构造方法里面调用就可以了