1.ViewStub好处
- ViewStub is a lightweight view with no dimension that doesn’t draw anything or participate in the layout. it's an invisible, zero-sized View that can be used to lazily inflate layout resources at runtime.
Android官方对ViewStub的解析:1.ViewStub一个不可见2.大小为0的试图. (下面会分析这两点实现)
ViewStub好处:显示优酷视频加载评论列表的ListView,当没有数据或者网络加载失败时,如果inflate空列表的ListView会占用资源;当有数据时,才会inflate列表的ListView,延迟加载了布局.
2.ViewStub使用步骤
<ViewStub
android:id="@+id/list_stub"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout="@layout/stub_list"
android:inflatedId="@+id/stub_list"/>
stub_list.xml文件
<ListView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
- 每一个ViewStub必须有android:layout属性,其中android:inflatedId的值就是被inflate的View的ID.
- findViewById(R.id.list_stub)).setVisibility(View.VISIBLE);
// or
ListView listView = (ListView)((ViewStub) findViewById(R.id.list_stub)).inflate();
可以通过这两种方式inflate布局,第二种方式inflate布局不需要findViewById()找ListView.查看源码发现,可以通过设置setOnInflateListener()回调监听获取inflate的View.
3.ViewStub源码分析
public ViewStub(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context);
final TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.ViewStub, defStyleAttr, defStyleRes);
// 解析android:inflatedId属性,其值是被inflate的View的ID
mInflatedId = a.getResourceId(R.styleable.ViewStub_inflatedId, NO_ID);
// 解析android:layout属性,其值是被inflate的View布局
mLayoutResource = a.getResourceId(R.styleable.ViewStub_layout, 0);
// 解析android:id属性,可以通过findViewByID找到该ViewStub
mID = a.getResourceId(R.styleable.ViewStub_id, NO_ID);
a.recycle();
// 最重要的两点
setVisibility(GONE); // 设置不可见
setWillNotDraw(true); // 本View不会调用onDraw()方法绘制内容
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 设置试图大小为0
setMeasuredDimension(0, 0);
}
public void setVisibility(int visibility) {
if (mInflatedViewRef != null) {
// 已经inflate()已经调用,直接获取该inflate的View控制可见性
View view = mInflatedViewRef.get();
if (view != null) {
view.setVisibility(visibility);
} else {
throw new IllegalStateException("setVisibility called on un-referenced view");
}
} else {
// 如果没有调用过inflate()方法,并且设置了试图可见,就会调用inflate()加载布局
super.setVisibility(visibility);
if (visibility == VISIBLE || visibility == INVISIBLE) {
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);
// 设置mInflatedId给inflate的View
if (mInflatedId != NO_ID) {
view.setId(mInflatedId);
}
// 获取ViewStub在视图中的位置
final int index = parent.indexOfChild(this);
// 从视图移除ViewStub
parent.removeViewInLayout(this);
final ViewGroup.LayoutParams layoutParams = getLayoutParams();
// 将inflate的试图加载父布局中,位置是被移除的ViewStub位置(也就是该ViewStub被替换成layoutView)
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");
}
}
// 设置回调监听
public void setOnInflateListener(OnInflateListener inflateListener) {
mInflateListener = inflateListener;
}
public static interface OnInflateListener {
// inflated:被inflate的View
void onInflate(ViewStub stub, View inflated);
}
4.ViewStub使用中注意事项
- 一旦调用setVisibility(View.VISIBLE)或者inflate()方法之后,该ViewStub将会从试图中被移除(此时调用findViewById()是找不到该ViewStub对象).
- 如果指定了mInflatedId , 被inflate的layoutView的id就是mInflatedId.
- 被inflate的layoutView的layoutParams与ViewStub的layoutParams相同.
以上三点注意的事项可以从源码中得知:
//注意事项第二点
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);
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。