if (mOverlay != null && !mOverlay.isEmpty()) {
mOverlay.getOverlayView().dispatchDraw(canvas);
}
// 完成
return;
}
}
我们选择常规的绘制过程,不介绍2,5步骤。
第一步,调用drawBackground绘制背景图案:
private void drawBackground(Canvas canvas) {
final Drawable background = mBackground;
// 获取到当前view的背景,是一个drawable对象 if (background == null) {
return;
}
if (mBackgroundSizeChanged) {// 判断背景大小是否变化,是则设置背景边界
background.setBounds(0, 0, mRight - mLeft, mBottom - mTop);
mBackgroundSizeChanged = false;
mPrivateFlags3 |= PFLAG3_OUTLINE_INVALID;
}
// Attempt to use a display list if requested.
if (canvas.isHardwareAccelerated() && mAttachInfo != null
&& mAttachInfo.mHardwareRenderer != null) {
mBackgroundRenderNode = getDrawableRenderNode(background, mBackgroundRenderNode);
final RenderNode displayList = mBackgroundRenderNode;
if (displayList != null && displayList.isValid()) {
setBackgroundDisplayListProperties(displayList);
((HardwareCanvas) canvas).drawRenderNode(displayList);
return;
}
}
// 调用drawable对象的绘制方法完成绘制
final int scrollX = mScrollX;
final int scrollY = mScrollY;
if ((scrollX | scrollY) == 0) {
background.draw(canvas);
} else {
canvas.translate(scrollX, scrollY);
background.draw(canvas);
canvas.translate(-scrollX, -scrollY);
}
}
第三步,调用onDraw方法绘制view的内容,由于不同的view内容不同,所以需要子类进行重写。
第四步,绘制子view,这里仍然需要当前layout的dispatchDraw方法来完成对各子view的绘制。
第六步,绘制滚动条。
通常情况下,我们自定义view,复写onDraw方法来绘制我们定义的view的内容即可。
总结
通过研究view类的源码,我们可以发现,在整个view的绘制流程中我们需要完成测定尺寸,布局定位,绘制这三个步骤。Android在设计过程中,将固定不变的流程设计为不可更改的模板方法,然而需要根据不同情况而定的内容则交给开发者来完成重写,在模板方法中调用即可。这样设计即保证了整个流程的完整,又给开发工作带来了灵活。同时,在类中又根据不同情况定义了不同的flag,来满足不同情况的绘制需求,以后有机会再具体研究这些flag的具体意义。