今天在开发过程中遇到一个很蛋痛的问题,最终发现是系统的问,值得总结一下。
前提
我在实现一个基于Adapter的LinearLayout的时候,想在第一个View中间绘制一个间隔线(Divider),接收一个Drawable对象,这是前提。
在绘制间隔线的时候,我的代码是这样的:
private void drawVerticalDividers(Canvas canvas) {
int count = mShowLastDivider ? getChildCount() : (getChildCount() - 1);
if (null != mDivider && count > 0) {
int height = mDividerSize;
int top = 0;
int offset = (mSpace - height) / 2;
View child = null;
Rect bounds = mTempRect;
bounds.left = getPaddingLeft();
bounds.right = bounds.left + getWidth() - getPaddingRight();
for (int i = 0; i < count; ++i) {
child = getChildAt(i);
top = child.getBottom() + offset;
bounds.top = top;
bounds.bottom = top + height;
drawDivider(canvas, bounds);
}
}
}
在每一个Child的下面绘制一个分隔线,这种算法是没有问题的。
在使用的时候,我设置一个ColorDrawable对象,运行在4.x的系统上面,完全没有问题,但是在2.x的系统上面,结束整个LinearLayout的背景色都变成了我设置的Divider的颜色,这很奇怪呀。我一直在怀疑是不是我的算法有问题,但最终一一排除,发现绘制Drawable的问题,最后就把源码拿出来看,果然,2.x版本的ColorDrawable与4.x的draw()方法实现不一样:
2.x版本的ColorDrawable#draw()实现:
@Override
public void draw(Canvas canvas) {
canvas.drawColor(mState.mUseColor);
}
它就简单粗暴地在整个Canvas上面绘制一个color,所以会导致整个View都成了指定的颜色
4.x版本的ColorDrawable#draw()实现
@Override
public void draw(Canvas canvas) {
if ((mState.mUseColor >>> 24) != 0) {
mPaint.setColor(mState.mUseColor);
canvas.drawRect(getBounds(), mPaint);
}
}
它是绘制一个bounds的Rect,所以它的绘制区域是我指定的bound。
我是怎么解决这个问题呢?
很简单,在绘制divider之前,用指定的bound来剪切Canvas:
final Drawable divider = mDivider;
if (null != divider) {
canvas.save();
canvas.clipRect(bounds);
divider.setBounds(bounds);
divider.draw(canvas);
canvas.restore();
}
这样就没有问题了。
总结:
只能说Android也在一步一步的完善,它的源码也在不断的进步,这是很好的,这也同时告诉我们,在开发Android应用程序的时候,要多注意到不同OS版本之间的差异性,每当Google推出新版本的OS的时候,要多多关注一下新功能,新改进,这样在开发过程中也能降低这种风险。