<ViewStub
android:id="@+id/view_stub"
android:layout_margin="10dp"
android:inflatedId="@+id/tv_title"
android:layout="@layout/tv_title_layout"
android:layout_width="220dp"
android:layout_height="50dp" />
複製代碼
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tv_title"
android:text="I'm inflate view."
android:textColor="#000"
android:textSize="15sp"
android:layout_width="match_parent"
android:layout_height="match_parent">
</TextView>
複製代碼
雖然,layout裏面佈局寫的 width 和 height 爲 match_parent,可是不生效,只會繼承於 viewstub 指定的大小。android
咱們在代碼裏面就能夠這樣寫:canvas
ViewStub viewStub = (ViewStub) findViewById(R.id.view_stub);
if (viewStub!=null) {
viewStub.inflate();
}
TextView tvTitle = (TextView) findViewById(R.id.tv_title);
tvTitle.setText("I'm inflate: " + System.currentTimeMillis());
複製代碼
private int mInflatedId;//viewstub傳遞給佈局的id
private int mLayoutResource;//viewstub的佈局
private WeakReference<View> mInflatedViewRef;
複製代碼
這裏有一個弱引用,是用來幹嗎的呢?咱們先無論,往下看。bash
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);
}
複製代碼
很普通,直接從xml佈局中讀取相應的屬性,而且在構造函數中就設置爲 GONE,接着:setWillNotDraw(true),設置一個標記,聲明這個View不作 onDraw 繪製。ide
/**
* If this view doesn't do any drawing on its own, set this flag to * allow further optimizations. By default, this flag is not set on * View, but could be set on some View subclasses such as ViewGroup. * * Typically, if you override {@link #onDraw(android.graphics.Canvas)} * you should clear this flag. * * @param willNotDraw whether or not this View draw on its own */ public void setWillNotDraw(boolean willNotDraw) { setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK); } 複製代碼
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(0, 0);
}
@Override
public void draw(Canvas canvas) {
}
複製代碼
measure直接傳入0,說明ViewStub初始化就是一個0大小的View。函數
從上面知道,inflate 或者 setVisibility 均可以加載佈局,咱們先看:setVisibility:源碼分析
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():佈局
public View inflate() {
final ViewParent viewParent = getParent();
if (viewParent != null && viewParent instanceof ViewGroup) {
if (mLayoutResource != 0) {
final ViewGroup parent = (ViewGroup) viewParent;
//mInflater 能夠從外部傳進來
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);
}
//獲取當前ViewStub在ViewGroup中的index
final int index = parent.indexOfChild(this);
//ViewStub替換成inflate後的View
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);
//inflate回調
if (mInflateListener != null) {
mInflateListener.onInflate(this, view);
}
return view;
}
//省略異常
}
//省略異常
}
複製代碼
public static interface OnInflateListener {
void onInflate(ViewStub stub, View inflated);
}
複製代碼
在 inflate 的時候會進行回調ui