本篇你将了解到:
- draw 的具体流程
- 简单的去重写 onDraw 方法
draw 方法
draw过程的主要流程如下:
- 绘制
background - 如果需要的话,保存
canvas的layer,来准备fading - 绘制
view的content(调用onDraw方法) - 绘制
children(dispatchDraw方法) - 如果需要的话,绘制
fading edges,然后还原layer - 绘制装饰器、比如
scrollBar
下方是伪代码,
public void draw(Canvas canvas) {
final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE &&
(mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);
// Step 3, draw the content 调用onDraw方法
if (!dirtyOpaque) onDraw(canvas);
// Step 4, draw the children
dispatchDraw(canvas);
// Step 6, draw decorations (foreground, scrollbars)
onDrawForeground(canvas);
}
其中标志位 dirtyOpaque 为 true 时,是不回去调用 onDraw 方法的。而 dirtyOpaque 其实是由 privateFlags 决定的。如果我们修改了 privateFlags 的值,就可以使重写 onDraw 被调用。
- 方法1:设置背景
设置背景的方法里会调用computeOpaqueFlags重新设置privateFlags。
public void setBackgroundDrawable(Drawable background) {
computeOpaqueFlags();
....省略一大段代码
computeOpaqueFlags();
....省略一点点代码
invalidate(true);
invalidateOutline();
}
- 方法2:调用
setWillNotDraw方法
同样也是修改privateFlags达到目的。
public void setWillNotDraw(boolean willNotDraw) {
setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK);
}
重写 onDraw
目标效果就是在上一章的 Layout 中,添加一个圆形图案。

image.png
关键代码:
var paint = Paint().let {
it.color = Color.YELLOW
it
}
/**
* 不设置 background 的话,不会调用该方法
*/
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
val x = measuredWidth / 2.0F
val y = measuredHeight / 2.0F
canvas?.drawCircle(x, y, Math.min(x, y), paint)
}
全部代码 -- AViewGroup:Github 地址,是 kotlin 写的
总结
Android View 框架(1)-- LayoutInflater
Android View 框架(2)-- measure
Android View 框架(3)-- layout
Android View 框架(4)-- draw