Android4.2源码View.draw(Canvas canvas)中canvas分析

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)函数进行绘制。



你可能感兴趣的:(源码,android,canvas)