ViewStub详解

ViewStub详解首先上源码:packageandroid.view;importandroid.annotation.IdRes;importandroid.annotation.LayoutRes;importandroid.content.Context;importandroid.content.res.TypedArray;importandroid.graphics.Canvas;importandroid.util.AttributeSet;importandroid.widg

大家好,又见面了,我是你们的朋友全栈君。

源码:

package android.view;
import android.annotation.IdRes;
import android.annotation.LayoutRes;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.widget.RemoteViews.RemoteView;
import com.android.internal.R;
import java.lang.ref.WeakReference;
/** * ViewStub是一个用户不可见的,大小为0的view,用于在app运行时懒加载一些布局。 *当ViewStub设置用户可见(setVisibility)时,或者当调用inflate()方法时,布局会就被初始化。ViewStub会用初始化后的布局文件替换自己放入其父布局中(参考inflate中的replaceSelfWithView方法)。 * * 因此ViewStub会在view布局中存在一直到setVisibility或inflate被调用了。 * * 当被初始化的View添加到ViewStub的父布局时会使用ViewStub的布局属性,因此你可以使用ViewStub的inflatedId属性定义/重写View的id。例如: * * * <ViewStub android:id="@+id/stub" * android:inflatedId="@+id/subTree" * android:layout="@layout/mySubTree" * android:layout_width="120dip" * android:layout_height="40dip" /> * * * 上面例子里边定义了一个id为stub的ViewStub。在初始化布局subTree之后,这个ViewStub就会从它父布局中移除。新创建的mySubTree布局的View的id就会使用布局中定义的subTree,最后这个新创建的view的宽为120dip,高为40dip. * * * 如下方式是最标准的初始化布局View的方式: * * * ViewStub stub = findViewById(R.id.stub); * View inflated = stub.inflate(); * * * 当inflate()方法被调用后,ViewStub会被替换为初始化后的布局View,并且View会被返回。从而让app获取到view的引用而不用在调用一次findViewById(). * * @attr ref android.R.styleable#ViewStub_inflatedId * @attr ref android.R.styleable#ViewStub_layout */
@RemoteView
public final class ViewStub extends View { 

private int mInflatedId;
private int mLayoutResource;
private WeakReference<View> mInflatedViewRef;
private LayoutInflater mInflater;
private OnInflateListener mInflateListener;
public ViewStub(Context context) { 

this(context, 0);
}
/** * 通过传入布局id创建ViewStub(猜测是用于代码中动态初始化时调用的)。 * * @param context The application's environment. * @param layoutResource The reference to a layout resource that will be inflated. */
public ViewStub(Context context, @LayoutRes int layoutResource) { 

this(context, null);
mLayoutResource = layoutResource;
}
public ViewStub(Context context, AttributeSet attrs) { 

this(context, attrs, 0);
}
public ViewStub(Context context, AttributeSet attrs, int defStyleAttr) { 

this(context, attrs, defStyleAttr, 0);
}
/** * 解析布局文件创建ViewStub,并获取mInflatedId及mLayoutResource等属性。最后设置不可见及不绘制自身。 * */
public ViewStub(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 

super(context);
final TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.ViewStub, defStyleAttr, defStyleRes);
saveAttributeDataForStyleable(context, R.styleable.ViewStub, attrs, a, 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);
}
/** * Returns the id taken by the inflated view. If the inflated id is * {@link View#NO_ID}, the inflated view keeps its original id. * * @return A positive integer used to identify the inflated view or * {@link #NO_ID} if the inflated view should keep its id. * * @see #setInflatedId(int) * @attr ref android.R.styleable#ViewStub_inflatedId */
@IdRes
public int getInflatedId() { 

return mInflatedId;
}
/** * Defines the id taken by the inflated view. If the inflated id is * {@link View#NO_ID}, the inflated view keeps its original id. * * @param inflatedId A positive integer used to identify the inflated view or * {@link #NO_ID} if the inflated view should keep its id. * * @see #getInflatedId() * @attr ref android.R.styleable#ViewStub_inflatedId */
@android.view.RemotableViewMethod(asyncImpl = "setInflatedIdAsync")
public void setInflatedId(@IdRes int inflatedId) { 

mInflatedId = inflatedId;
}
/** @hide **/
public Runnable setInflatedIdAsync(@IdRes int inflatedId) { 

mInflatedId = inflatedId;
return null;
}
/** * Returns the layout resource that will be used by {@link #setVisibility(int)} or * {@link #inflate()} to replace this StubbedView * in its parent by another view. * * @return The layout resource identifier used to inflate the new View. * * @see #setLayoutResource(int) * @see #setVisibility(int) * @see #inflate() * @attr ref android.R.styleable#ViewStub_layout */
@LayoutRes
public int getLayoutResource() { 

return mLayoutResource;
}
/** * Specifies the layout resource to inflate when this StubbedView becomes visible or invisible * or when {@link #inflate()} is invoked. The View created by inflating the layout resource is * used to replace this StubbedView in its parent. * * @param layoutResource A valid layout resource identifier (different from 0.) * * @see #getLayoutResource() * @see #setVisibility(int) * @see #inflate() * @attr ref android.R.styleable#ViewStub_layout */
@android.view.RemotableViewMethod(asyncImpl = "setLayoutResourceAsync")
public void setLayoutResource(@LayoutRes int layoutResource) { 

mLayoutResource = layoutResource;
}
/** @hide **/
public Runnable setLayoutResourceAsync(@LayoutRes int layoutResource) { 

mLayoutResource = layoutResource;
return null;
}
/** * Set {@link LayoutInflater} to use in {@link #inflate()}, or {@code null} * to use the default. */
public void setLayoutInflater(LayoutInflater inflater) { 

mInflater = inflater;
}
/** * Get current {@link LayoutInflater} used in {@link #inflate()}. */
public LayoutInflater getLayoutInflater() { 

return mInflater;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 

setMeasuredDimension(0, 0);
}
/** * 不做任何绘制,所以比普通view节省了时间与内存。 */
@Override
public void draw(Canvas canvas) { 

}
@Override
protected void dispatchDraw(Canvas canvas) { 

}
/** * 当设置visibility为VISIBLE或INVISIBLE时,inflate方法就会被调用 * ,且初始化出来的view对象会替换StubView在其父布局中的位置。 * * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. * * @see #inflate() */
@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();
}
}
}
/** @hide **/
public Runnable setVisibilityAsync(int visibility) { 

if (visibility == VISIBLE || visibility == INVISIBLE) { 

ViewGroup parent = (ViewGroup) getParent();
return new ViewReplaceRunnable(inflateViewNoAdd(parent));
} else { 

return null;
}
}
private View inflateViewNoAdd(ViewGroup parent) { 

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);
}
return view;
}
private void replaceSelfWithView(View view, ViewGroup parent) { 

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);
}
}
/** * 初始化布局view,替换stub在父布局中的位置(注:stub被替换之后getparent会为空,因此会抛出IllegalArgumentException异常)。 * * * @return The inflated layout resource. * */
public View inflate() { 

final ViewParent viewParent = getParent();
if (viewParent != null && viewParent instanceof ViewGroup) { 

if (mLayoutResource != 0) { 

final ViewGroup parent = (ViewGroup) viewParent;
final View view = inflateViewNoAdd(parent);
replaceSelfWithView(view, parent);
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");
}
}
/** * Specifies the inflate listener to be notified after this ViewStub successfully * inflated its layout resource. * * @param inflateListener The OnInflateListener to notify of successful inflation. * * @see android.view.ViewStub.OnInflateListener */
public void setOnInflateListener(OnInflateListener inflateListener) { 

mInflateListener = inflateListener;
}
/** * 接收布局view被创建的观察者,如果设置了会在布局view被初始化之后回调 listener的onInflate方法。 * * * @see android.view.ViewStub#setOnInflateListener(android.view.ViewStub.OnInflateListener) */
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);
}
/** @hide **/
public class ViewReplaceRunnable implements Runnable { 

public final View view;
ViewReplaceRunnable(View view) { 

this.view = view;
}
@Override
public void run() { 

replaceSelfWithView(view, (ViewGroup) getParent());
}
}
}

使用方法:
1.在布局中定义ViewStub:

<ViewStub android:id="@+id/stub" android:inflatedId="@+id/subTree" android:layout="@layout/mySubTree" android:layout_width="120dip" android:layout_height="40dip" />

2.布局中使用:

	 ViewStub stub = findViewById(R.id.stub);
//inflated就是初始化后的布局view对象
View inflated = stub.inflate();
//对inflated操作,设置文字,图片等。

抛砖引玉,不当之处敬请之处,万分感谢?。

注:其实也可以也可以用动态添加的方法添加View:在java/kotlin代码中动态初始化View,然后添加到对应的viewgroup中。

1.在需要的时候通过layoutInflater.inflate(mLayoutResource, parent, false);

2.方法初始化要添加的view,然后调用对应viewGroup.addView(View child/View child, int index/View child, LayoutParams params);方法添加到布局中;

这样的话在布局中就不用多了个ViewStub的view了,性能也更好些。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/153965.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 删除卡巴斯基激活码

    删除卡巴斯基激活码

  • PDF文档免费转成Word文档,不限页数。

    PDF文档免费转成Word文档,不限页数。链接:https://download.csdn.net/download/auspicious_air/10942678断网状态下输入序列号Name:SolidConverterPDFv9E-mail:user@ru.ruOrganization:anyUnlockCode:KTGK

  • 基于知识图谱的知识推理

    基于知识图谱的知识推理这基于知识图谱的知识推理基本概念、定义推理方法分为三类:知识图推理的相关应用基于规则的推理基于表示学习的推理基于神经网络和强化学习的推理基本概念、定义人工智能算法必须具有推理能力,推理过程必须依赖于知识工程时代的先验知识和经验,大量知识图(KGs),如YAGO(Suchanek,Kasnki,2008),WordNet(Miller,1995),Freebase(Bollacker,Evans、Paritosh、Sturge和Taylor,2008)已经开发。KGs包含大量的先验知识,同时也能有效地组织

  • LAMP配置-php.ini

    LAMP配置-php.ini[PHP]zlib.output_compression=Offimplicit_flush=Offunserialize_callback_func=serialize_precision=-1disable_functions=disable_classes=zend.enable_gc=Onexpose_php=Onmax_execution_time=30max_input_time=60memory_limit=128.

  • 网易开源镜像站_阿里云开源镜像站

    网易开源镜像站_阿里云开源镜像站网易开源镜像站http://mirrors.163.com/配置163yum的方法:1.进入开源镜像站http://mirrors.163.com/2.进入对应系统的"

  • 乱码问题分析

    乱码问题分析字符乱码的事,估计大家都遇到过,很烦,什么utf-8、GBK、GB2312转来转去,不知道什么时候才能转正常。我们做个试验,如果你是windows系统,打开记事本,新建一个文件,输入”联通”两个字之后,保存,关闭,然后再次打开,出现了什么现象?乱码!那你赶紧去找IT吧,你中招了!开玩笑的,这是著名的“windows联通之谜事件”。继续往下看,后面会有谜底的解释。那么我们就讨论下字符编码哪些事吧,首

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号