最近在使用ViewStub,在使用的过程中遇到了一些问题,所以现在就在这里记录一下,也免得后面使用的人少走一些坑。事情是这样的,由于项目中要用ViewStub对原有的一些布局页面进行懒加载,提升用户体验,所以简单了解了一下ViewStub的用法后,就将原来的需要懒加载的Layout单独设置为一个xml文件。本来以为是没有问题,但是一看原来并不是这么简单。有好几个需要注意的点,现在分开来讲:
一、ViewStub多次inflate引发的exception:
ViewStub must have a non-null ViewGroup viewParent 相信第一次用的人应该都会遇到过这个的问题,我们进去inflate()的方法源码看看,
public View inflate() {
final ViewParent viewParent = getParent();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);
}
parent.addView(view, index, layoutParams);
} else {
parent.addView(view, index);
}
mInflateListener.onInflate(this, view);
}
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