public ViewStub(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context);
final TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.ViewStub, defStyleAttr, defStyleRes);
// 获取inflatedId属性,如果xml没有设置inflatedId属性,
//那么mInflatedId属性为NO_ID,即为-1
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();
//设置可见性为GONE
setVisibility(GONE);
//设置不绘制
setWillNotDraw(true);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//设置宽高都为0
setMeasuredDimension(0, 0);
}
@Override
@android.view.RemotableViewMethod(asyncImpl = "setVisibilityAsync")
public void setVisibility(int visibility) {
//mInflatedViewRef为弱引用,保存的为目标视图对象
//,是在inflate()方法中赋的值
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) {
//当设置View.Visible或者View.Invisible时,
//调用inflate()方法
inflate();
}
}
public View inflate() {
//获取ViewStub的父视图
final ViewParent viewParent = getParent();
if (viewParent != null && viewParent instanceof ViewGroup) {
//判断在xml中是否设置了layout属性,若没有设置,mLayoutResource为0
if (mLayoutResource != 0) {
final ViewGroup parent = (ViewGroup) viewParent;
//初始化目标视图
final View view = inflateViewNoAdd(parent);
//把目标视图添加到根布局中,同时从根布局删除当前的ViewStub
replaceSelfWithView(view, parent);
//把目标视图对象保存在弱引用mInflatedViewRef中,因为ViewStub.setVisibility
//操作的是目标视图并非当前ViewStub视图
mInflatedViewRef = new WeakReference<>(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");
}
}
private View inflateViewNoAdd(ViewGroup parent) {
final LayoutInflater factory;
if (mInflater != null) {
factory = mInflater;
} else {
factory = LayoutInflater.from(mContext);
}
//根据资源id mLayoutResuource加载目标视图
final View view = factory.inflate(mLayoutResource, parent, false);
//把xml中ViewStub设置的inflateId设置为目标视图的根Id
if (mInflatedId != NO_ID) {
view.setId(mInflatedId);
}
return view;
}
private void replaceSelfWithView(View view, ViewGroup parent) {
//查找自己在父视图中的位置index,添加目标视图的时候需要这个参数
final int index = parent.indexOfChild(this);
//删除自己在父视图中
parent.removeViewInLayout(this);
//获取布局参数,就是layout_with,layout_height之类的
final ViewGroup.LayoutParams layoutParams = getLayoutParams();
//如果布局参数不为空,就把布局参数设置为目标视图根布局的参数,
//同时把目标视图添加到父视图中
if (layoutParams != null) {
parent.addView(view, index, layoutParams);
} else {
parent.addView(view, index);
}
}
//目标视图加载成功后回调接口
public static interface OnInflateListener {
/**
* Invoked after a ViewStub successfully inflated its layout resource.
* This method is invoked after the inflated view was added to the
* hierarchy but before the layout pass.
*
* @param stub The ViewStub that initiated the inflation.
* @param inflated The inflated View.
*/
void onInflate(ViewStub stub, View inflated);
}
Android布局优化(二) ViewStub源码解析
最新推荐文章于 2021-10-05 18:21:00 发布