正确使用ViewStub

最近在使用ViewStub,在使用的过程中遇到了一些问题,所以现在就在这里记录一下,也免得后面使用的人少走一些坑。事情是这样的,由于项目中要用ViewStub对原有的一些布局页面进行懒加载,提升用户体验,所以简单了解了一下ViewStub的用法后,就将原来的需要懒加载的Layout单独设置为一个xml文件。本来以为是没有问题,但是一看原来并不是这么简单。有好几个需要注意的点,现在分开来讲:

一、ViewStub多次inflate引发的exception:

ViewStub must have a non-null ViewGroup viewParent 相信第一次用的人应该都会遇到过这个的问题,我们进去inflate()的方法源码看看,

public View inflate() {

final ViewParent viewParent = getParent();
if (viewParent != null && viewParent instanceof ViewGroup) {
if (mLayoutResource != 0) {
final ViewGroup parent = (ViewGroup) viewParent;
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);
}
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);
}
mInflatedViewRef = new WeakReference<View>(view);
if (mInflateListener != null) {
mInflateListener.onInflate(this, view);
}
return view;
} else {
throw new IllegalArgumentException("ViewStub must have a valid layoutResource");
}
}

是不是很熟悉?由于ViewStub第一次inflate的时候,就已经将需要显示的布局替换掉自己了,所以第二次inflate的时候,getParent()是null,所以就会报异常。解决方法是inflate()的时候将view保存起来,然后下次判断这个View是否为NUll,如果是null就inflate().否则就直接使用这个view,还有一种就是setOnInflateListener,这个网上也有文章,这里不细说。如果被包含的layout的子View没有用户逻辑操作的,可以使用ViewStub的setVisibility()来控制显示和隐藏。里面已经做了inflate多次的判断的了,不会有异常的。

二、被包含的layout里面设置layout_margin属性失效而设置padding属性有效的问题。这个问题需要看源码才能解答,所以就看了一下源码。还是看inflate()方法。

final ViewGroup.LayoutParams layoutParams = getLayoutParams();
if (layoutParams != null) {
parent.addView(view, index, layoutParams);
else {
parent.addView(view, index);
}

看到这一段代码了吗?有个getLayoutParams() 以及 parent.addView方法。可以看到,getlayoutParams获取的是VeiwStub的LayoutParams,而不是被显示的Layout_params。所以,addView的时候,要么就是将ViewStub的layoutParams赋值给将要显示的view,要么直接调用addView(view,index),所以如果想要margin有效果,我们之能将layout_margin放到ViewStub里面,同理,如果是在相对布局里面,below_  above_这些属性控制都要放到viewStub那里,而不是放到将要显示的layout里面。那为什么padding会在将要显示的layout中起作用呢?这就要好好理解一下ViewGroup.LayoutParams layoutParams了,你会发现padding并不属于ViewGroup.LayoutParams layoutParams里面的,而是属于View的成员变量,这也就解释了为什么padding属性不会失效了,之前还以为padding设置ViewGroup.LayoutParams里面设置的呢。好了,这里相信大家对ViewStub都有一个很清晰的了解了,有什么问题,可以相互交流哦,如何比较优雅的使用ViewStub呢?经过本人试验,个人还是比较推荐使用setOnInflateListener,因为它只会被调用一次,就是刚inflate的时候,而且无论无论inflate的layout中是不是有其它的事件监听,它都可以实现。

我建了个qq群:207678498

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值