2023年7月15日发(作者:)
ViewStub的使⽤和源码分析ViewStub的使⽤xml⽂件 可以看到,ViewStub必须添加layout,这个是它需要展⽰的东西。inflatedId则可以加也可以不加,并不影响显⽰。它的作⽤是inflateId 表⽰给被引⽤/填充的 layout 资源设置⼀个id,通过它可以获取到被引⽤/填充的 layout 的 View 实例。然后显⽰的时候可以调⽤inflate()得到⼀个 view = viewstub_e();隐藏的时候调⽤setVisibility()viewstub_ibility(BLE);源码分析ViewStub的创建public final class ViewStub extends View{}ViewStub是集成于View的,所以它的创建也是调⽤createViewFromTag(),createViewFromTag有多个重载⽅法,最终调⽤的是View createViewFromTag(View parent, String name, Context context, AttributeSet attrs, boolean ignoreThemeAttr) { if (("view")) { name = ributeValue(null, "class"); } ...... try { View view = tryCreateView(parent, name, context, attrs); if (view == null) { final Object lastContext = mConstructorArgs[0]; mConstructorArgs[0] = context; try { if (-1 == f('.')) { view = onCreateView(context, parent, name, attrs); } else { view = createView(context, name, null, attrs); } } finally { mConstructorArgs[0] = lastContext; } } return view; } catch (InflateException e) { throw e; }
}主要看下⾯的代码if (-1 == f('.')) { view = onCreateView(context, parent, name, attrs);} else { view = createView(context, name, null, attrs);}根据标签⾥⾯有没有.来区分是⾃定义的控件,还是系统⾃带的控件 从上⾯可以知道,系统的控件在使⽤的时候直接写这个控件就好,⽽⾃定义的控件则需要写全路径。@Nullable public final View createView(@NonNull Context viewContext, @NonNull String name, @Nullable String prefix, @Nullable AttributeSet attrs) throws ClassNotFoundException, InflateException { eNonNull(viewContext); eNonNull(name); Constructor extends View> constructor = (name); if (constructor != null && !verifyClassLoader(constructor)) { constructor = null; (name); } Class extends View> clazz = null; try { egin(_TAG_VIEW, name); if (constructor == null) { // Class not found in the cache, see if it's real, and try to add it clazz = e(prefix != null ? (prefix + name) : name, false, ssLoader()).asSubclass(); if (mFilter != null && clazz != null) { boolean allowed = Class(clazz); if (!allowed) { failNotAllowed(name, prefix, viewContext, attrs); } } constructor = structor(mConstructorSignature); essible(true); (name, constructor); } else { // If we have a filter, apply it to cached constructor if (mFilter != null) { // Have we seen this name before? Boolean allowedState = (name); if (allowedState == null) { // New class -- remember whether it is allowed clazz = e(prefix != null ? (prefix + name) : name, false, ssLoader()).asSubclass(); boolean allowed = clazz != null && Class(clazz); (name, allowed); if (!allowed) { failNotAllowed(name, prefix, viewContext, attrs); } } else if (()) { failNotAllowed(name, prefix, viewContext, attrs); } } } try { final View view = tance(args); if (view instanceof ViewStub) { // Use the same context when inflating ViewStub later. final ViewStub viewStub = (ViewStub) view; outInflater(cloneInContext((Context) args[0])); } return view; } finally { mConstructorArgs[0] = lastContext; } } }在createView()主要做了以下⼏件事。1、从map中获取构造函数对象,如果不存在,则通过反射的⽅式创建⼀个实例,并保存在map中。2、创建好构造函数实例之后调⽤newInstance(),创建⼀个view.如果view属于ViewStub,则返回去。此时ViewStub则创建好了。ViewStub的构造函数public ViewStub(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context); final TypedArray a = StyledAttributes(attrs, ub, defStyleAttr, defStyleRes); saveAttributeDataForStyleable(context, ub, attrs, a, defStyleAttr, defStyleRes); mInflatedId = ourceId(ub_inflatedId, NO_ID); mLayoutResource = ourceId(ub_layout, 0); mID = ourceId(ub_id, NO_ID); e(); setVisibility(GONE); setWillNotDraw(true); }在ViewStub构造函数中,setVisibility(GONE)表⽰将视图设置为不可见,并且不会去绘制。这也是在布局优化的时候会使⽤ibility()public void setVisibility(int visibility) { if (mInflatedViewRef != null) { View view = (); if (view != null) { ibility(visibility); } else { throw new IllegalStateException("setVisibility called on un-referenced view"); } } else { ibility(visibility); if (visibility == VISIBLE || visibility == INVISIBLE) { inflate(); } } }当我们第⼀次进去的时候mInflatedViewRef是为null的,则会⾛else逻辑。由于我们在构造⽅法中setVisibility(GONE),则不会⾛inflate(),这样就不会显⽰ViewStub所指定的layout资源。那如果想要加载ViewStub所指定的layout资源,需要设置ViewStub控件设置可见,或者调⽤inflate()⽅法。特别注意:setVisibility(int visibility)⽅法,参数visibility对应三个值分别是INVISIBLE、VISIBLE、GONEVISIBLE:视图可见INVISIBLE:视图不可见的,它仍然占⽤布局的空间GONE:视图不可见,它不占⽤布局的空间inflate()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) { ate(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"); } }在inflate()主要做了以下⼏件事:1、调⽤inflateViewNoAdd⽅法返回android:layout指定的布局⽂件最顶层的view2、调⽤replaceSelfWithView⽅法, 移除ViewStub, 添加view到被移除的ViewStub的位置3、初始化mInflatedViewRef,添加view到 mInflatedViewRef 中4、加载完成之后,回调onInflate ⽅法这样第⼆次进来的时候,在setVisibility()就会⾛if的逻辑,通过setVISIBLE或者INVISIBLE来显⽰和不显⽰。ViewStub的注意事项1、使⽤ViewStub需要在xml中设置android:layout,不是layout,否则会抛出异常throw new IllegalArgumentException("ViewStub must have a valid layoutResource");2、ViewStub不能作为根布局,它需要放在ViewGroup中, 否则会抛出异常throw new IllegalStateException("ViewStub must have a non-null ViewGroup viewParent");3、⼀旦调⽤setVisibility(E)或者inflate()⽅法之后,该ViewStub将会从试图中被移除(此时调⽤findViewById()是找不到该ViewStub对象).// 获取ViewStub在视图中的位置final int index = fChild(this);// 移除ViewStub// 注意:调⽤removeViewInLayout⽅法之后,调⽤findViewById()是找不到该ViewStub对象ViewInLayout(this);4、如果指定了mInflatedId , 被inflate的layoutView的id就是mInflatedId// mInflatedId 是在xml设置的 inflateIdif (mInflatedId != NO_ID) { // 将id复制给view (mInflatedId); //注意:如果指定了mInflatedId , 被inflate的layoutView的id就是mInflatedId}5、被inflate的layoutView的layoutParams与ViewStub的layoutParams相同.final Params layoutParams = getLayoutParams();// 将xml中指定的 android:layout 布局⽂件中最顶层的View 也就是根view,// 添加到被移除的 ViewStub的位置if (layoutParams != null) { w(view, index, layoutParams);} else { w(view, index);}
发布者:admin,转转请注明出处:http://www.yc00.com/web/1689430946a247110.html
评论列表(0条)