ViewStub
什么时候使用ViewStub?为什么使用?
需要控制某个View显示或者隐藏的话,会把需要的View写在布局上,然后通过View.GONE/View.InVisible设置可见性;这样虽然操作简单,但是还是耗费资源,因为即使view不可见,还是可以被父窗体控制,还是会被创建对象,还是会被实例化,还是会被设置属性。
Android.view.ViewStub是一个大小为0,默认不可见的控件,只有给它设置成了View.Visiable或者调用了inflate()才会填充布局资源,占用的资源少。推荐使用ViewStub;
基本介绍
ViewStub是一个不可见,大小为0的视图,可以在运行过程中延时加载布局资源;
当ViewStub被设置成可见,或者它的inflate()被调用的时候,布局资源才会被填充,然后ViewStub本身就会被填充起来的布局资源替换掉,它在视图树里面就不存在了,被填充的布局在替换ViewStub的时候会使用ViewStub的布局参数(LayoutParameters),如height,width等;也可以通过ViewStub的inflateId属性定义或者重写被填充布局资源的Id。
总结
o ViewStub引用布局时,使用layout属性,取值@layout/XXXX;
o InflateId表示给被引用布局的ID,也就是被控制显示或隐藏的布局的id;
o 如果不写inflateId的话,如果需要可以在被引用的布局中直接给出id属性;
o inflate()方法只能被调用一次,如果再调用会报异常信息,ViewStub must have a non null ViewGrounp ViewParent,
ViewStub使用inflate()将其引用的布局view展示出来之后,ViewStub本身就会从视图树里面被移除,此时ViewStub就获取不到它的父布局,而inflate()一上来就需要获取它的父布局,然后根据父布局是否为空再去执行具体的填充逻辑,如果一开始就是空,就会报出上面的错误。
所以如果inflate()之后如果还想调用ViewStub引用的布局view,就需要在调用inflate()的时候使用try–catch(),当catch到异常的时候调用setVisibility()设置ViewStub的View.Visible即可。
o ViewStub里面的setVisibility()里面也多次调用inflate(),这个时候为什么不会崩溃?
ViewStub的setVisibility()里面会先判断WeakReference类型的成员变量mInflatedViewRef是否为空,第一次调用setVisibility()的时候,mInflatedViewRef没有被初始化,所以为Null,这个时候就会走inflate,在inflate()里面创建起来的布局填充一个WeakReference弱引用,并且赋值给mInflatedViewRef,从而完成mInflateViewRef的初始化;
第二次调用setVisibility()的时候,mInflatedViewRef不是null,就会调用WeakReference的父类Reference里面的get()方法获取该引用指向的实体对象,也就是说通过get()拿到被填充的对象view,然后再走View的setVisibility()。
o ViewStub的inflate()只能被调用一次;
如果想控制/修改被填充布局里面的内容并重复显示被填充的view,就用try将viewStub.inflate()方法以及修改内容的代码包裹起来,并在catch里面setVisibility。
o 在xml中定义ViewStub结点的时候,内部不能包含其他节点,也就是说ViewStub是一个自闭和结点,如果一个布局/View想通过ViewStub显示,只能定义在单独的xml文件中。