ViewGroup.java中绘制从dispatchDraw()开始,这里的Canvas由ViewRootImpl.java中传入,此时Canvas是屏幕大小的画布。
@Override
protected void dispatchDraw(Canvas canvas) {
...
more |= drawChild(canvas, child, drawingTime);
}
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
return child.draw(canvas, this, drawingTime);
}
drawChild函数只有一句话,指向了View.java的draw(Canvas canvas, ViewGroup parent, long drawingTime)函数。(这个函数不同于draw(Canvas canvas)函数,后者是View绘制过程开始的地方)
boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
...
int sx = 0;
int sy = 0;
if (!hasDisplayList) {
computeScroll();
sx = mScrollX;
sy = mScrollY;
}
final boolean hasNoCache = cache == null || hasDisplayList;
final boolean offsetForScroll = cache == null && !hasDisplayList &&
layerType != LAYER_TYPE_HARDWARE;
int restoreTo = -1;
if (!useDisplayListProperties || transformToApply != null) {
restoreTo = canvas.save();
}
if (offsetForScroll) {
canvas.translate(mLeft - sx, mTop - sy);
} else {
if (!useDisplayListProperties) {
canvas.translate(mLeft, mTop);
}
if (scalingRequired) {
if (useDisplayListProperties) {
// TODO: Might not need this if we put everything inside the DL
restoreTo = canvas.save();
}
// mAttachInfo cannot be null, otherwise scalingRequired == false
final float scale = 1.0f / mAttachInfo.mApplicationScale;
canvas.scale(scale, scale);
}
}
...
if (!layerRendered) {
if (!hasDisplayList) {
// Fast path for layouts with no backgrounds
if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
mPrivateFlags &= ~PFLAG_DIRTY_MASK;
if (DBG_DRAW) {
Xlog.d(VIEW_LOG_TAG, "view draw1 : calling dispatchDraw,this = " + this);
}
dispatchDraw(canvas);
} else {
if (DBG_DRAW) {
Xlog.d(VIEW_LOG_TAG, "view draw1 : calling draw,this = " + this);
}
draw(canvas);
}
} else {
mPrivateFlags &= ~PFLAG_DIRTY_MASK;
((HardwareCanvas) canvas).drawDisplayList(displayList, null, flags);
...
}
上面这段代码,有两个需要指出的地方,一个就是canvas.translate()函数,这里表明了ViewRootImpl传进来的Canvas需要根据子视图本身的布局大小进行裁减,也就是说屏幕上所有子视图的canvas都只是一块裁减后的大小的canvas,当然这也就是为什么子视图的canvas的坐标原点不是从屏幕左上角开始,而是它自身大小的左上角开始的原因。
第二个需要指出的是如果ViewGroup的子视图仍然是ViewGroup,那么它会回调dispatchDraw(canvas)进行分法,如果子视图是View,那么就调用View的draw(canvas)函数进行绘制。