最近公司做一个国外的项目,因为国外的网络环境还有手机型号配置可能和国内大不一样,涉及到一些内存、CPU等一些相关的问题,下面针对一些页面可能涉及到显示隐藏层叠过多导致界面渲染过度浪费内存空间推荐一个控件,对,没错,它就是ViewStub,在某些场景中,并不一定需要把所有的内容都展示出来,可以隐藏一些View视图,待用户需要展示的时候再加载到当前的Layout中,这个时候就可以用到ViewStub这个控件了,这样可以减少资源的消耗,使最初的加载速度变快。下面我们就直接进入案例代码吧!
1、主布局定义一个引用ViewStub布局xml
<ViewStub
android:id="@+id/viewstub_demo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout="@layout/viewstub_demo" />
2、viewstub_demo.xml需要去引用的布局
<ImageView
android:id="@+id/img_show"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
3、在activity里的onCreate初始化你的ViewStub
viewStub_album = findViewById(R.id.viewstub_demo);
4、比如说现在有一个这样的需求:就是当你有数据的时候显示,没有就隐藏,通过发起网络请求最终通过view.getDataSuccess()如下:
@Override
public void getDataSuccess(Data data) {
if (data== null || data.size() == 0) {
viewStub.setVisibility(View.GONE);
} else {
if (!isInflate_flag) {
View view = viewStub.inflate();
img_show = view.findViewById(R.id.img_show);
//如果这个图片需要去设置点击事件
img_show.setOnClickListener(this);
//设置图片数据Glide......
}
}
}
说明一下:inflate 方法只能被调用一次,因为调用后viewStub对象就被移除了视图树; 所以,如果此时再次点击显示按钮,就会崩溃,错误信息:ViewStub must have a non-null ViewGroupviewParent;有两种解决方法:
方法1:所以使用try catch ,当此处发现exception 的时候,在catch中使用setVisibility()重新显示;
方法2:设置一个Boolean类型的变量,标记viewstub是否已经inflate,如果viewstub还未inflate则执行初始化操作,反之则不进行操作。其中要使用ViewStub中OnInflateListener()监听事件来判断是否已经填充,从而保证viewstub不重复的inflate。
viewStub_demo.setOnInflateListener(new ViewStub.OnInflateListener() {
@Override
public void onInflate(ViewStub stub, View inflated) {
isInflate_flag = true;
//显示的时候去做一些操作
}
});
在这我用的是方法2,通过定义boolean类型的全局isInflate_flag变量,默认false,然后监听OnInflateListener在里面更改一下isInflate_flag的值为true,上述方法这也是通过百度查看其他大神的解决方法,🙏🙏
还有一个问题,就是关于ViewStub控件的android:inflateId属性,关于android:inflatedId解释——ViewStub设置的被映射的布局文件中的跟节点的Id,inflate之后可以通过findViewById获取到对应的被映射的布局对象。
最后总结一下ViewStub特点:
- ViewStub只能Inflate一次,之后ViewStub对象会被置为空。按句话说,某个被ViewStub指定的布局被Inflate后,就不会够再通过ViewStub来控制它了。
- ViewStub只能用来Inflate一个布局文件,而不是某个具体的View,当然也可以把View写在某个布局文件中。
基于以上的特点,那么可以考虑使用ViewStub的情况有:
- 在程序的运行期间,某个布局在Inflate后,就不会有变化,除非重新启动。
因为ViewStub只能Inflate一次,之后会被置空,所以无法指望后面接着使用ViewStub来控制布局。所以当需要在运行时不止一次的显示和隐藏某个布局,那么ViewStub是做不到的。这时就只能使用View的可见性来控制了。 - 想要控制显示与隐藏的是一个布局文件,而非某个View。
因为设置给ViewStub的只能是某个布局文件的Id,所以无法让它来控制某个View,所以,如果想要控制某个View(如Button或TextView)的显示与隐藏,或者想要在运行时不断的显示 与隐藏某个布局或View,只能使用View的可见性来控制。
上面是我自己通过实践和不断的去查找 ViewStub资料以及查看大神的博客最后撰写一些浅浅的理解以及基础用法,如果有兴趣的朋友可以去查看一下里面的api源码进行探索,毕竟学无止境嘛,如果上述有错误还请大佬们指出,不胜感激🙏🙏第一次写,有些地方可能写的不够好,还请各位大神多多包涵🙏