这个网上总结的很多,见android 关于 clipToPadding 和 clipChildren区别和作用
最近遇到的一处android ui问题最终使用clipToPadding得到了完美的解决,下面谈下个人对clipToPadding的理解。
- 这个是ViewGroup的属性,View是没有的
- clipToPadding必须与paddingTop等属性一起用,不然没有任何意义
- 默认的值是true,即padding范围内子控件不做任何layout和draw的动作,RecyclerView等边界处的显示效果也是在padding范围外的。
- 如果设置为false,那么子控件layout任然是在padding外的(不然padding还有啥意义),draw当然也是在padding外的,这个是一般情况。如果子控件有任何位移动画的话,这个值为false的意义就有了,它在padding范围内依然会显示!!!
- 网上我搜索到的例子全部是和RecyclerView,listView或者是ViewPager有关的,这个是clipToPadding使用最广泛的场景。即在列表组件头部和尾部添加padding,如果是直接加padding的话,可以看到就是把RecyclerView头部和尾部削掉,拖动的时候padding范围内是没有任何显示的,拖动到底的动画效果也是显示在padding范围外的。当设置clipToPadding为false的时候哦,设置padding的效果其实就是相当于设置了headView和FooterView,滑动到底的时候才有padding,其余的显示和拖动padding范围内也是占据的,这个是大多数期望的效果。
下面看下RecyclerView的源码就很清楚了:
@Override
public void setClipToPadding(boolean clipToPadding) {
if (clipToPadding != mClipToPadding) {
invalidateGlows();
}
mClipToPadding = clipToPadding;
super.setClipToPadding(clipToPadding);
if (mFirstLayoutComplete) {
requestLayout();
}
}
除了调用super的方法外,还用成员变量mClipToPadding保存了设置的值
void ensureTopGlow() {
if (mTopGlow != null) {
return;
}
mTopGlow = mEdgeEffectFactory.createEdgeEffect(this, EdgeEffectFactory.DIRECTION_TOP);
if (mClipToPadding) {
mTopGlow.setSize(getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
getMeasuredHeight() - getPaddingTop() - getPaddingBottom());
} else {
mTopGlow.setSize(getMeasuredWidth(), getMeasuredHeight());
}
}
top边界效果,mClipToPadding值为true的话size要考虑4个padding的限制,而为false的话就不用考虑了
public void draw(Canvas c) {
super.draw(c);
...
if (mTopGlow != null && !mTopGlow.isFinished()) {
final int restore = c.save();
if (mClipToPadding) {
c.translate(getPaddingLeft(), getPaddingTop());
}
needsInvalidate |= mTopGlow != null && mTopGlow.draw(c);
c.restoreToCount(restore);
}
...
}
draw的代码,只关心mTopGlow的处理,mClipToPadding为true的话要绘制的时候要依据padding做平移,而为false的话则不用考虑,这样边界效果虽然设置了padding,显示的时候却不用考虑padding,这也就是mClipToPadding的意义啊。
同理在拖动的时候,内容依然是可以在padding范围内显示的,好像没有padding一样。clipToPadding就好像是针对列表组件特定的一样,对于普通的ViewGroup并无多大意义。