4.View绘制分析笔记之onDraw

上一篇文章我们了解了View的onLayout,那么今天我们来学习Android View绘制三部曲的最后一步,onDraw,绘制。

ViewRootImpl#performDraw

private void performDraw() {

···    final boolean fullRedrawNeeded = mFullRedrawNeeded;    mFullRedrawNeeded = false;

mIsDrawing = true;    Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");    try {        draw(fullRedrawNeeded);    } finally {       mIsDrawing = false;        Trace.traceEnd(Trace.TRACE_TAG_VIEW);    }

···

}

performDraw主要的作用是调用ViewRootImpl#draw方法,并传递一个mFullRedrawNeeded参数,这个参数就是告诉draw方法,是否需要整体重新绘制,所以,我们把重点放在ViewRootImpl#draw这里。

ViewRootImpl#draw

下面代码为draw方法的关键代码

private void draw(boolean fullRedrawNeeded) {    //省略    ···    //生成绘制区域    final Rect dirty = mDirty;    //如果需要全屏绘制,则将dirty区域宽高设为全屏    if (fullRedrawNeeded) {        mAttachInfo.mIgnoreDirtyState = true;        dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));    }    //省略    ···    //调用drawSoftware方法,并传递dirty区域    if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)) {        return;    }}

ViewRootImpl#drawSoftware

private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,        boolean scalingRequired, Rect dirty) {

//通过dirty区域,获取并锁定canvas,后续传给decorView    final Canvas canvas;    try {        final int left = dirty.left;        final int top = dirty.top;        final int right = dirty.right;        final int bottom = dirty.bottom;

canvas = mSurface.lockCanvas(dirty);    } catch (Surface.OutOfResourcesException e) {        handleOutOfResourcesException(e);        return false;    } catch (IllegalArgumentException e) {        mLayoutRequested = true;            return false;    }    //省略    ···    //开始调用decorView的draw方法    mView.draw(canvas);}

View#draw

终于到了View的部分,View的draw方法,答题包括了6个步骤,稍后我们通过源代码进行逐步分析。

@CallSuperpublic void draw(Canvas canvas) {    final int privateFlags = mPrivateFlags;    //获取dirty区域是否不透明    final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE &&            (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);    //将flag22位21位设置为off,并且将PFLAG_DRAWN设置为on    mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;

//下面的注释是google对view的draw方法的6步分解注释      /*     * Draw traversal performs several drawing steps which must be executed     * in the appropriate order:     *     *      1. Draw the background     *      2. If necessary, save the canvas‘ layers to prepare for fading     *      3. Draw view‘s content     *      4. Draw children     *      5. If necessary, draw the fading edges and restore layers     *      6. Draw decorations (scrollbars for instance)     */

// 第一步,绘制背景,如果需要的话。    int saveCount;    // 如果dirty区域是不透明的,则跳过绘制背景。    if (!dirtyOpaque) {        drawBackground(canvas);    }

// 大多数情况(不需要绘制边界阴影的情况)都不需要2和5这两部,跳过    final int viewFlags = mViewFlags;    // 是否需要绘制横向边界阴影    boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;    // 是否需要绘制竖向向边界阴影    boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;    // 不需要绘制横向和竖向阴影,执行3,4,6步    if (!verticalEdges && !horizontalEdges) {        // Step 3, draw the content        if (!dirtyOpaque) onDraw(canvas);

// Step 4, draw the children        dispatchDraw(canvas);

// Overlay is part of the content and draws beneath Foreground        if (mOverlay != null && !mOverlay.isEmpty()) {            mOverlay.getOverlayView().dispatchDraw(canvas);        }

// Step 6, draw decorations (foreground, scrollbars)        onDrawForeground(canvas);

// we‘re done...        return;    }

/*     * Here we do the full fledged routine...     * (this is an uncommon case where speed matters less,     * this is why we repeat some of the tests that have been     * done above)     */    // 需要绘制阴影的话,则执行全部2-6的流程,不过这个流程并不常见,而且性能和速度上也不是很优秀。     boolean drawTop = false;    boolean drawBottom = false;    boolean drawLeft = false;    boolean drawRight = false;

float topFadeStrength = 0.0f;    float bottomFadeStrength = 0.0f;    float leftFadeStrength = 0.0f;    float rightFadeStrength = 0.0f;

// 第二步,保存fading相关的canvas图层信息    int paddingLeft = mPaddingLeft;

final boolean offsetRequired = isPaddingOffsetRequired();    if (offsetRequired) {        paddingLeft += getLeftPaddingOffset();    }

int left = mScrollX + paddingLeft;    int right = left + mRight - mLeft - mPaddingRight - paddingLeft;    int top = mScrollY + getFadeTop(offsetRequired);    int bottom = top + getFadeHeight(offsetRequired);

if (offsetRequired) {        right += getRightPaddingOffset();        bottom += getBottomPaddingOffset();    }

final ScrollabilityCache scrollabilityCache = mScrollCache;    final float fadeHeight = scrollabilityCache.fadingEdgeLength;    int length = (int) fadeHeight;

// clip the fade length if top and bottom fades overlap    // overlapping fades produce odd-looking artifacts    if (verticalEdges && (top + length > bottom - length)) {        length = (bottom - top) / 2;    }

// also clip horizontal fades if necessary    if (horizontalEdges && (left + length > right - length)) {        length = (right - left) / 2;    }

if (verticalEdges) {        topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength()));        drawTop = topFadeStrength * fadeHeight > 1.0f;        bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength()));        drawBottom = bottomFadeStrength * fadeHeight > 1.0f;    }

if (horizontalEdges) {        leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength()));        drawLeft = leftFadeStrength * fadeHeight > 1.0f;        rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength()));        drawRight = rightFadeStrength * fadeHeight > 1.0f;    }

saveCount = canvas.getSaveCount();

int solidColor = getSolidColor();    if (solidColor == 0) {        final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;

if (drawTop) {            canvas.saveLayer(left, top, right, top + length, null, flags);        }

if (drawBottom) {            canvas.saveLayer(left, bottom - length, right, bottom, null, flags);        }

if (drawLeft) {            canvas.saveLayer(left, top, left + length, bottom, null, flags);        }

if (drawRight) {            canvas.saveLayer(right - length, top, right, bottom, null, flags);        }    } else {        scrollabilityCache.setFadeColor(solidColor);    }

// 第三步,如果不是透明的,则调用onDraw方法进行绘制    if (!dirtyOpaque) onDraw(canvas);

// 第四步,调用dispatchDraw方法,绘制子View    dispatchDraw(canvas);

// 第五步,绘制阴影边缘    final Paint p = scrollabilityCache.paint;    final Matrix matrix = scrollabilityCache.matrix;    final Shader fade = scrollabilityCache.shader;

if (drawTop) {        matrix.setScale(1, fadeHeight * topFadeStrength);        matrix.postTranslate(left, top);        fade.setLocalMatrix(matrix);        p.setShader(fade);        canvas.drawRect(left, top, right, top + length, p);    }

if (drawBottom) {        matrix.setScale(1, fadeHeight * bottomFadeStrength);        matrix.postRotate(180);        matrix.postTranslate(left, bottom);        fade.setLocalMatrix(matrix);        p.setShader(fade);        canvas.drawRect(left, bottom - length, right, bottom, p);    }

if (drawLeft) {        matrix.setScale(1, fadeHeight * leftFadeStrength);        matrix.postRotate(-90);        matrix.postTranslate(left, top);        fade.setLocalMatrix(matrix);        p.setShader(fade);        canvas.drawRect(left, top, left + length, bottom, p);    }

if (drawRight) {        matrix.setScale(1, fadeHeight * rightFadeStrength);        matrix.postRotate(90);        matrix.postTranslate(right, top);        fade.setLocalMatrix(matrix);        p.setShader(fade);        canvas.drawRect(right - length, top, right, bottom, p);    }

canvas.restoreToCount(saveCount);

// 绘制覆盖物,这个覆盖物在前景图的下面(API18引入)    if (mOverlay != null && !mOverlay.isEmpty()) {        mOverlay.getOverlayView().dispatchDraw(canvas);    }    // 第六步,绘制前景图    onDrawForeground(canvas);}

View#drawBackground

这是第一步,绘制背景

private void drawBackground(Canvas canvas) {    final Drawable background = mBackground;    if (background == null) {        return;    }    //如果背景边界发生变化,则重新设置边界大小    setBackgroundBounds();

// 如果设置了硬件加速,则使用 display list 绘制背景    if (canvas.isHardwareAccelerated() && mAttachInfo != null            && mAttachInfo.mHardwareRenderer != null) {        mBackgroundRenderNode = getDrawableRenderNode(background, mBackgroundRenderNode);

final RenderNode renderNode = mBackgroundRenderNode;        if (renderNode != null && renderNode.isValid()) {            setBackgroundRenderNodeProperties(renderNode);            ((DisplayListCanvas) canvas).drawRenderNode(renderNode);            return;        }    }

//获取滑动偏移量,如果有偏移,则先把canvas移动,然后绘制背景,最后再移动回来。    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);    }}

ViewGroup#dispatchDraw

这里是第四步,绘制子View,dispatchDraw方法由ViewGroup实现。

protected void dispatchDraw(Canvas canvas) {    boolean usingRenderNodeProperties = canvas.isRecordingFor(mRenderNode);    final int childrenCount = mChildrenCount;    final View[] children = mChildren;    int flags = mGroupFlags;    //查看FLAG_RUN_ANIMATION是否是on,如果是的话,则为子View设置动画,并启动动画    if ((flags & FLAG_RUN_ANIMATION) != 0 && canAnimate()) {        final boolean buildCache = !isHardwareAccelerated();        for (int i = 0; i < childrenCount; i++) {            final View child = children[i];            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {                final LayoutParams params = child.getLayoutParams();                attachLayoutAnimationParameters(child, params, i, childrenCount);                bindLayoutAnimation(child);            }        }

final LayoutAnimationController controller = mLayoutAnimationController;        if (controller.willOverlap()) {            mGroupFlags |= FLAG_OPTIMIZE_INVALIDATE;        }

controller.start();

mGroupFlags &= ~FLAG_RUN_ANIMATION;        mGroupFlags &= ~FLAG_ANIMATION_DONE;

if (mAnimationListener != null) {            mAnimationListener.onAnimationStart(controller.getAnimation());        }    }

int clipSaveCount = 0;    // 对canvas设置padding区域    final boolean clipToPadding = (flags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK;    if (clipToPadding) {        clipSaveCount = canvas.save();        canvas.clipRect(mScrollX + mPaddingLeft, mScrollY + mPaddingTop,                mScrollX + mRight - mLeft - mPaddingRight,                mScrollY + mBottom - mTop - mPaddingBottom);    }

// 我们将启动子View的动画,所以把这里的PFLAG_DRAW_ANIMATION置为off    mPrivateFlags &= ~PFLAG_DRAW_ANIMATION;    mGroupFlags &= ~FLAG_INVALIDATE_REQUIRED;

boolean more = false;    //获取绘图时开始的时间    final long drawingTime = getDrawingTime();

if (usingRenderNodeProperties) canvas.insertReorderBarrier();    final int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();    int transientIndex = transientCount != 0 ? 0 : -1;    // 如果启用硬件加速,那么就不支持view绘制优先级了,硬件内部会处理绘制的先后顺序    final ArrayList<View> preorderedList = usingRenderNodeProperties            ? null : buildOrderedChildList();    final boolean customOrder = preorderedList == null            && isChildrenDrawingOrderEnabled();    for (int i = 0; i < childrenCount; i++) {        //绘制瞬态视图,        //目前瞬态视图的add方法是在两年前android M中加入进来的,目前还是@hide的,        //所以transientIndex是-1,所以这个while循环不会执行到,        //可能这段代码是google为以后的功能做的铺垫。        while (transientIndex >= 0 && mTransientIndices.get(transientIndex) == i) {            final View transientChild = mTransientViews.get(transientIndex);            if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE ||                    transientChild.getAnimation() != null) {                more |= drawChild(canvas, transientChild, drawingTime);            }            transientIndex++;            if (transientIndex >= transientCount) {                transientIndex = -1;            }        }

//按绘制顺序获取子View index        final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);        //通过index获取需要绘制的View,并执行drawChild方法        final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);        if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {            //绘制子View,下面详细介绍            more |= drawChild(canvas, child, drawingTime);        }    }    //绘制瞬态View,略过,可能会在以后的某个版本中    while (transientIndex >= 0) {        // there may be additional transient views after the normal views        final View transientChild = mTransientViews.get(transientIndex);        if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE ||                transientChild.getAnimation() != null) {            more |= drawChild(canvas, transientChild, drawingTime);        }        transientIndex++;        if (transientIndex >= transientCount) {            break;        }    }    if (preorderedList != null) preorderedList.clear();

// 绘制正在消失的View(还没结束动画)    if (mDisappearingChildren != null) {        final ArrayList<View> disappearingChildren = mDisappearingChildren;        final int disappearingCount = disappearingChildren.size() - 1;        // Go backwards -- we may delete as animations finish        for (int i = disappearingCount; i >= 0; i--) {            final View child = disappearingChildren.get(i);            more |= drawChild(canvas, child, drawingTime);        }    }    if (usingRenderNodeProperties) canvas.insertInorderBarrier();

if (debugDraw()) {        onDebugDraw(canvas);    }

if (clipToPadding) {        canvas.restoreToCount(clipSaveCount);    }

// 如果FLAG_INVALIDATE_REQUIRED是on,则调用invalidate刷新    flags = mGroupFlags;

if ((flags & FLAG_INVALIDATE_REQUIRED) == FLAG_INVALIDATE_REQUIRED) {        invalidate(true);    }

//动画结束后发出通知,并擦除缓存    if ((flags & FLAG_ANIMATION_DONE) == 0 && (flags & FLAG_NOTIFY_ANIMATION_LISTENER) == 0 &&            mLayoutAnimationController.isDone() && !more) {        // We want to erase the drawing cache and notify the listener after the        // next frame is drawn because one extra invalidate() is caused by        // drawChild() after the animation is over        mGroupFlags |= FLAG_NOTIFY_ANIMATION_LISTENER;        final Runnable end = new Runnable() {           @Override           public void run() {               notifyAnimationListener();           }        };        post(end);    }}

View#draw(Canvas canvas, ViewGroup parent, long drawingTime)

这个方法是被ViewGroup调用,让子View来绘制自己的。该方法是View基于 layer type 以及硬件加速来专门处理渲染行为的代码段。

boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {    final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated();    /* If an attached view draws to a HW canvas, it may use its RenderNode + DisplayList.     *     * If a view is dettached, its DisplayList shouldn‘t exist. If the canvas isn‘t     * HW accelerated, it can‘t handle drawing RenderNodes.     */    // 检测是否启动硬件加速    boolean drawingWithRenderNode = mAttachInfo != null            && mAttachInfo.mHardwareAccelerated            && hardwareAcceleratedCanvas;

boolean more = false;    final boolean childHasIdentityMatrix = hasIdentityMatrix();    final int parentFlags = parent.mGroupFlags;

if ((parentFlags & ViewGroup.FLAG_CLEAR_TRANSFORMATION) != 0) {        parent.getChildTransformation().clear();        parent.mGroupFlags &= ~ViewGroup.FLAG_CLEAR_TRANSFORMATION;    }

Transformation transformToApply = null;    boolean concatMatrix = false;    final boolean scalingRequired = mAttachInfo != null && mAttachInfo.mScalingRequired;    final Animation a = getAnimation();    if (a != null) {        more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired);        concatMatrix = a.willChangeTransformationMatrix();        if (concatMatrix) {            mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM;        }        transformToApply = parent.getChildTransformation();    } else {        if ((mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_TRANSFORM) != 0) {            // 不再执行动画,全部清除掉            mRenderNode.setAnimationMatrix(null);            mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_TRANSFORM;        }        if (!drawingWithRenderNode                && (parentFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {            final Transformation t = parent.getChildTransformation();            final boolean hasTransform = parent.getChildStaticTransformation(this, t);            if (hasTransform) {                final int transformType = t.getTransformationType();                transformToApply = transformType != Transformation.TYPE_IDENTITY ? t : null;                concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0;            }        }    }

concatMatrix |= !childHasIdentityMatrix;

// 尽早设置PFLAG_DRAWN参数,使invalidate()可以成功调用    mPrivateFlags |= PFLAG_DRAWN;

if (!concatMatrix &&            (parentFlags & (ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS |                    ViewGroup.FLAG_CLIP_CHILDREN)) == ViewGroup.FLAG_CLIP_CHILDREN &&            canvas.quickReject(mLeft, mTop, mRight, mBottom, Canvas.EdgeType.BW) &&            (mPrivateFlags & PFLAG_DRAW_ANIMATION) == 0) {        mPrivateFlags2 |= PFLAG2_VIEW_QUICK_REJECTED;        return more;    }    mPrivateFlags2 &= ~PFLAG2_VIEW_QUICK_REJECTED;

if (hardwareAcceleratedCanvas) {        // 清楚PFLAG_INVALIDATED标志位        mRecreateDisplayList = (mPrivateFlags & PFLAG_INVALIDATED) != 0;        mPrivateFlags &= ~PFLAG_INVALIDATED;    }

RenderNode renderNode = null;    Bitmap cache = null;    int layerType = getLayerType(); // TODO: signify cache state with just ‘cache‘ local    if (layerType == LAYER_TYPE_SOFTWARE || !drawingWithRenderNode) {         if (layerType != LAYER_TYPE_NONE) {             // 如果没有RenderNode,则使用SW绘制             layerType = LAYER_TYPE_SOFTWARE;             buildDrawingCache(true);        }        cache = getDrawingCache(true);    }

if (drawingWithRenderNode) {        // 延迟获取Display List,直到animation-driven alpha的值被设置好。        renderNode = updateDisplayListIfDirty();        if (!renderNode.isValid()) {            // 不常见的,略过            renderNode = null;            drawingWithRenderNode = false;        }    }

//下面是对view当前状态的分析,scale、alpha和translate,然后对canvas进行调整。    int sx = 0;    int sy = 0;    if (!drawingWithRenderNode) {        computeScroll();        sx = mScrollX;        sy = mScrollY;    }

final boolean drawingWithDrawingCache = cache != null && !drawingWithRenderNode;    final boolean offsetForScroll = cache == null && !drawingWithRenderNode;

int restoreTo = -1;    if (!drawingWithRenderNode || transformToApply != null) {        restoreTo = canvas.save();    }    if (offsetForScroll) {        canvas.translate(mLeft - sx, mTop - sy);    } else {        if (!drawingWithRenderNode) {            canvas.translate(mLeft, mTop);        }        if (scalingRequired) {            if (drawingWithRenderNode) {                // 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);        }    }

float alpha = drawingWithRenderNode ? 1 : (getAlpha() * getTransitionAlpha());    if (transformToApply != null            || alpha < 1            || !hasIdentityMatrix()            || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) {        if (transformToApply != null || !childHasIdentityMatrix) {            int transX = 0;            int transY = 0;

if (offsetForScroll) {                transX = -sx;                transY = -sy;            }

if (transformToApply != null) {                if (concatMatrix) {                    if (drawingWithRenderNode) {                        renderNode.setAnimationMatrix(transformToApply.getMatrix());                    } else {                        // Undo the scroll translation, apply the transformation matrix,                        // then redo the scroll translate to get the correct result.                        canvas.translate(-transX, -transY);                        canvas.concat(transformToApply.getMatrix());                        canvas.translate(transX, transY);                    }                    parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION;                }

float transformAlpha = transformToApply.getAlpha();                if (transformAlpha < 1) {                    alpha *= transformAlpha;                    parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION;                }            }

if (!childHasIdentityMatrix && !drawingWithRenderNode) {                canvas.translate(-transX, -transY);                canvas.concat(getMatrix());                canvas.translate(transX, transY);            }        }

// Deal with alpha if it is or used to be <1        if (alpha < 1 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) {            if (alpha < 1) {                mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_ALPHA;            } else {                mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_ALPHA;            }            parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION;            if (!drawingWithDrawingCache) {                final int multipliedAlpha = (int) (255 * alpha);                if (!onSetAlpha(multipliedAlpha)) {                    if (drawingWithRenderNode) {                        renderNode.setAlpha(alpha * getAlpha() * getTransitionAlpha());                    } else if (layerType == LAYER_TYPE_NONE) {                        canvas.saveLayerAlpha(sx, sy, sx + getWidth(), sy + getHeight(),                                multipliedAlpha);                    }                } else {                    // Alpha is handled by the child directly, clobber the layer‘s alpha                    mPrivateFlags |= PFLAG_ALPHA_SET;                }            }        }    } else if ((mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) {        onSetAlpha(255);        mPrivateFlags &= ~PFLAG_ALPHA_SET;    }    if (!drawingWithRenderNode) {        // apply clips directly, since RenderNode won‘t do it for this draw        if ((parentFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0 && cache == null) {            if (offsetForScroll) {                canvas.clipRect(sx, sy, sx + getWidth(), sy + getHeight());            } else {                if (!scalingRequired || cache == null) {                    canvas.clipRect(0, 0, getWidth(), getHeight());                } else {                    canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight());                }            }        }        if (mClipBounds != null) {            // clip bounds ignore scroll            canvas.clipRect(mClipBounds);        }    }        // 这里调用子View的draw方法,并将调整好的canvas传进去    if (!drawingWithDrawingCache) {        if (drawingWithRenderNode) {            mPrivateFlags &= ~PFLAG_DIRTY_MASK;            ((DisplayListCanvas) canvas).drawRenderNode(renderNode);        } else {            // Fast path for layouts with no backgrounds            if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {                mPrivateFlags &= ~PFLAG_DIRTY_MASK;                dispatchDraw(canvas);            } else {                draw(canvas);            }        }    }     // 如果是cache模式,则利用cache    else if (cache != null) {        mPrivateFlags &= ~PFLAG_DIRTY_MASK;        if (layerType == LAYER_TYPE_NONE || mLayerPaint == null) {            // no layer paint, use temporary paint to draw bitmap            Paint cachePaint = parent.mCachePaint;            if (cachePaint == null) {                cachePaint = new Paint();                cachePaint.setDither(false);                parent.mCachePaint = cachePaint;            }            cachePaint.setAlpha((int) (alpha * 255));            canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint);        } else {            // use layer paint to draw the bitmap, merging the two alphas, but also restore            int layerPaintAlpha = mLayerPaint.getAlpha();            if (alpha < 1) {                mLayerPaint.setAlpha((int) (alpha * layerPaintAlpha));            }            canvas.drawBitmap(cache, 0.0f, 0.0f, mLayerPaint);            if (alpha < 1) {                mLayerPaint.setAlpha(layerPaintAlpha);            }        }    }    if (restoreTo >= 0) {        canvas.restoreToCount(restoreTo);    }    if (a != null && !more) {        if (!hardwareAcceleratedCanvas && !a.getFillAfter()) {            onSetAlpha(255);        }        parent.finishAnimatingView(this, a);    }    if (more && hardwareAcceleratedCanvas) {        if (a.hasAlpha() && (mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) {            // alpha animations should cause the child to recreate its display list            invalidate(true);        }    }    mRecreateDisplayList = false;    return more;}

到这里,整个View及子View的绘制的调用就基本完成了,剩下的就交给各个View的onDraw方法去实现不同的绘制。

时序图

图为View绘制时序图

小结

View的绘制大体是6步来进行。

  1. 绘制背景
  2. 保存fade canvas信息
  3. 调用onDraw
  4. dispatchDraw,遍历绘制子View
  5. 绘制fade
  6. 绘制前景

源码中还有不少涉及到硬件加速、RenderNode、display list、动画的代码,后续会专门进行研究。

到这篇文章截止,View视图三部曲就结束了,感谢阅读。

系列文章

Android 视图及View绘制分析笔记之setContentView
View绘制分析笔记之onMeasure
View绘制分析笔记之onLayout
View绘制分析笔记之onDraw

时间: 2024-10-11 17:30:13

4.View绘制分析笔记之onDraw的相关文章

3.View绘制分析笔记之onLayout

上一篇文章我们了解了View的onMeasure,那么今天我们继续来学习Android View绘制三部曲的第二步,onLayout,布局. ViewRootImpl#performLayout private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth, int desiredWindowHeight) { mLayoutRequested = false; mScrollMayChange

1.Android 视图及View绘制分析笔记之setContentView

自从1983年第一台图形用户界面的个人电脑问世以来,几乎所有的PC操作系统都支持可视化操作,Android也不例外.对于所有Android Developer来说,我们接触最多的控件就是View.通常,我们使用自定义View,需要了解最多的除了事件分发,就是View的绘制过程.然而关于View的绘制,涉及到的知识点纷繁复杂,这么多的代码知识,要梳理起来,肯定是先要找个头.那么平常我们用的最多的方法是哪个方法呢?当然是setContentView()! setContentView 首先我们直接在

2.View绘制分析笔记之onMeasure

今天主要学习记录一下Android View绘制三部曲的第一步,onMeasure,测量. 起源 在Activity中,所有的View都是DecorView的子View,然后DecorView又是被ViewRootImpl所控制,当Activity显示的时候,ViewRootImpl的performTranversals方法开始运行,这个方法很长,不过核心的三个流程就是依次调用performMeasure.performLayout.performDraw三个方法,从而完成DecorView的绘

Android View绘制及实践

概述 整个View树的绘图流程是在ViewRoot.java类的performTraversals()函数展开的,该函数做的执行过程可简单概况为: - 判断是否需要重新计算视图大小(measure) - 判断是否重新需要安置视图的位置(layout) - 判断是否需要重绘(draw) 其整个流程图如下: 图片来自:Android 开源项目源码解析 公共技术点中的 View 绘制流程 在Android中View的整个生命周期,调用invalidate和requestLayout会触发一系列的方法,

Android中View绘制流程以及invalidate()等相关方法分析

前言: 本文是我读<Android内核剖析>第13章----View工作原理总结而成的,在此膜拜下作者 .同时真挚地向渴望了解 Android 框架层的网友,推荐这本书,希望你们能够在Android开发里学到更多的知识 . 整个View树的绘图流程是在ViewRoot.java类的performTraversals()函数展开的,该函数做的执行过程可简单概况为 根据之前设置的状态,判断是否需要重新计算视图大小(measure).是否重新需要安置视图的位置(layout).以及是否需要重绘 (d

Android中View绘制流程分析

创建Window 在Activity的attach方法中通过调用PolicyManager.makeNewWindo创建Window,将一个View add到WindowManager时,WindowManagerImpl创建一个ViewRoot来管理该窗口的根View.并通过ViewRoot.setView方法把该View传给ViewRoot. final void attach(Context context, ActivityThread aThread, Instrumentation

Android视图View绘制流程与源码分析(全)

来源:[工匠若水 http://blog.csdn.net/yanbober] 1 背景 还记得前面<Android应用setContentView与LayoutInflater加载解析机制源码分析>这篇文章吗?我们有分析到Activity中界面加载显示的基本流程原理,记不记得最终分析结果就是下面的关系: 看见没有,如上图中id为content的内容就是整个View树的结构,所以对每个具体View对象的操作,其实就是个递归的实现. 前面<Android触摸屏事件派发机制详解与源码分析一(

从ViewRootImpl类分析View绘制的流程(一)

[出处:从ViewRootImpl类分析View绘制的流程 CSDN 废墟的树] 从上两篇博客 <从setContentView方法分析Android加载布局流程> 和 <从LayoutInflater分析XML布局解析成View的树形结构的过程> 中我们了解到Activity视图UI是怎么添加到Activity的根布局DecorView上面的. 我们知道Activity中的PhoneView对象帮我们创建了一个PhoneView内部类DecorView(父类为FrameLayou

从ViewRootImpl类分析View绘制的流程

[转载请注明出处:从ViewRootImpl类分析View绘制的流程 CSDN 废墟的树] 从上两篇博客 <从setContentView方法分析Android加载布局流程> 和 <从LayoutInflater分析XML布局解析成View的树形结构的过程> 中我们了解到Activity视图UI是怎么添加到Activity的根布局DecorView上面的. 我们知道Activity中的PhoneView对象帮我们创建了一个PhoneView内部类DecorView(父类为Frame