今天在開發過程中遇到一個很蛋痛的問題,最終發現是系統的問,值得總結一下。
前提
我在實作一個基于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的時候,要多多關注一下新功能,新改進,這樣在開發過程中也能降低這種風險。