View绘制最开始是从最顶层DecorView开始的,在ViewRootImpl中的performTraversals方法中,调用了 performDraw,开始对DecorView进行绘制:

 private void performDraw() {        if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {            return;        }        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);        }        // For whatever reason we didn't create a HardwareRenderer, end any        // hardware animations that are now dangling        if (mAttachInfo.mPendingAnimatingRenderNodes != null) {            final int count = mAttachInfo.mPendingAnimatingRenderNodes.size();            for (int i = 0; i < count; i++) {                mAttachInfo.mPendingAnimatingRenderNodes.get(i).endAllAnimators();            }            mAttachInfo.mPendingAnimatingRenderNodes.clear();        }        if (mReportNextDraw) {            mReportNextDraw = false;            if (mAttachInfo.mHardwareRenderer != null) {                mAttachInfo.mHardwareRenderer.fence();            }            if (LOCAL_LOGV) {                Log.v(TAG, "FINISHED DRAWING: " + mWindowAttributes.getTitle());            }            if (mSurfaceHolder != null && mSurface.isValid()) {                mSurfaceHolderCallback.surfaceRedrawNeeded(mSurfaceHolder);                SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();                if (callbacks != null) {                    for (SurfaceHolder.Callback c : callbacks) {                        if (c instanceof SurfaceHolder.Callback2) {                            ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(                                    mSurfaceHolder);                        }                    }                }            }            try {                mWindowSession.finishDrawing(mWindow);            } catch (RemoteException e) {            }        }    }

12行调用draw(fullRedrawNeeded),在draw方法里面,又调用了
drawSoftware:

 private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,            boolean scalingRequired, Rect dirty) {        // Draw with software renderer.        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);            // The dirty rectangle can be modified by Surface.lockCanvas()            //noinspection ConstantConditions            if (left != dirty.left || top != dirty.top || right != dirty.right                    || bottom != dirty.bottom) {                attachInfo.mIgnoreDirtyState = true;            }            // TODO: Do this in native            canvas.setDensity(mDensity);        } catch (Surface.OutOfResourcesException e) {            handleOutOfResourcesException(e);            return false;        } catch (IllegalArgumentException e) {            Log.e(TAG, "Could not lock surface", e);            // Don't assume this is due to out of memory, it could be            // something else, and if it is something else then we could            // kill stuff (or ourself) for no reason.            mLayoutRequested = true;    // ask wm for a new surface next time.            return false;        }        try {            if (DEBUG_ORIENTATION || DEBUG_DRAW) {                Log.v(TAG, "Surface " + surface + " drawing to bitmap w="                        + canvas.getWidth() + ", h=" + canvas.getHeight());                //canvas.drawARGB(255, 255, 0, 0);            }            // If this bitmap's format includes an alpha channel, we            // need to clear it before drawing so that the child will            // properly re-composite its drawing on a transparent            // background. This automatically respects the clip/dirty region            // or            // If we are applying an offset, we need to clear the area            // where the offset doesn't appear to avoid having garbage            // left in the blank areas.            if (!canvas.isOpaque() || yoff != 0 || xoff != 0) {                canvas.drawColor(0, PorterDuff.Mode.CLEAR);            }            dirty.setEmpty();            mIsAnimating = false;            attachInfo.mDrawingTime = SystemClock.uptimeMillis();            mView.mPrivateFlags |= View.PFLAG_DRAWN;            if (DEBUG_DRAW) {                Context cxt = mView.getContext();                Log.i(TAG, "Drawing: package:" + cxt.getPackageName() +                        ", metrics=" + cxt.getResources().getDisplayMetrics() +                        ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo());            }            try {                canvas.translate(-xoff, -yoff);                if (mTranslator != null) {                    mTranslator.translateCanvas(canvas);                }                canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0);                attachInfo.mSetIgnoreDirtyState = false;                mView.draw(canvas);                drawAccessibilityFocusedDrawableIfNeeded(canvas);            } finally {                if (!attachInfo.mSetIgnoreDirtyState) {                    // Only clear the flag if it was not set during the mView.draw() call                    attachInfo.mIgnoreDirtyState = false;                }            }        } finally {            try {                surface.unlockCanvasAndPost(canvas);            } catch (IllegalArgumentException e) {                Log.e(TAG, "Could not unlock surface", e);                mLayoutRequested = true;    // ask wm for a new surface next time.                //noinspection ReturnInsideFinallyBlock                return false;            }            if (LOCAL_LOGV) {                Log.v(TAG, "Surface " + surface + " unlockCanvasAndPost");            }        }        return true;    }

73行,执行mView.draw(canvas),mView就是DecorView的实例,会先调用DecorView的draw方法:

public void draw(Canvas canvas) {            super.draw(canvas);            if (mMenuBackground != null) {                mMenuBackground.draw(canvas);            }        }

在DecorView的draw方法里面,执行super.draw(canvas),会调用FrameLayout的draw方法:

public void draw(Canvas canvas) {        super.draw(canvas);        if (mForeground != null) {            final Drawable foreground = mForeground;            if (mForegroundBoundsChanged) {                mForegroundBoundsChanged = false;                final Rect selfBounds = mSelfBounds;                final Rect overlayBounds = mOverlayBounds;                final int w = mRight-mLeft;                final int h = mBottom-mTop;                if (mForegroundInPadding) {                    selfBounds.set(0, 0, w, h);                } else {                    selfBounds.set(mPaddingLeft, mPaddingTop, w - mPaddingRight, h - mPaddingBottom);                }                final int layoutDirection = getLayoutDirection();                Gravity.apply(mForegroundGravity, foreground.getIntrinsicWidth(),                        foreground.getIntrinsicHeight(), selfBounds, overlayBounds,                        layoutDirection);                foreground.setBounds(overlayBounds);            }            foreground.draw(canvas);        }    }

在FrameLayout的draw方法里面,最先执行 super.draw(canvas),也就是调用View的draw方法:

public void draw(Canvas canvas) {        final int privateFlags = mPrivateFlags;        final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE &&                (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);        mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;        /* * 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) */        // Step 1, draw the background, if needed        int saveCount;        if (!dirtyOpaque) {            drawBackground(canvas);        }        // skip step 2 & 5 if possible (common case)        final int viewFlags = mViewFlags;        boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;        boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;        if (!verticalEdges && !horizontalEdges) {            // Step 3, draw the content            if (!dirtyOpaque) onDraw(canvas);            // Step 4, draw the children            dispatchDraw(canvas);            // Step 6, draw decorations (scrollbars)            onDrawScrollBars(canvas);            if (mOverlay != null && !mOverlay.isEmpty()) {                mOverlay.getOverlayView().dispatchDraw(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) */        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;        // Step 2, save the canvas' layers        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);        }        // Step 3, draw the content        if (!dirtyOpaque) onDraw(canvas);        // Step 4, draw the children        dispatchDraw(canvas);        // Step 5, draw the fade effect and restore layers        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);        // Step 6, draw decorations (scrollbars)        onDrawScrollBars(canvas);        if (mOverlay != null && !mOverlay.isEmpty()) {            mOverlay.getOverlayView().dispatchDraw(canvas);        }    }

View的绘制一般分为6个步骤,在draw方法里面已经列出来了:
第一步:绘制View背景。
第二步:保存canvas的状态,准备绘制FadingEdge(边框阴影),这个不是必要的步骤。
第三步:调用onDraw方法,绘制View的内容。
第四步:调用dispatchDraw,如果是ViewGroup,则绘制子View。
第五步:绘制FadingEdge(边框阴影),恢复canvas的状态,这个不是必须的步骤。
第六步:绘制View的滑动条。
执行这六个步骤之后,View的绘制就完成了。重点关注第四步,执行dispatchDraw方法:

    protected void dispatchDraw(Canvas canvas) {    }

View的dispatchDraw是空的,只有ViewGroup才需要绘制子View,DecorView是FrameLayout,但是FrameLayout没有重写dispatchDraw方法,那么会执行ViewGroup的dispatchDraw方法:

 protected void dispatchDraw(Canvas canvas) {        boolean usingRenderNodeProperties = canvas.isRecordingFor(mRenderNode);        final int childrenCount = mChildrenCount;        final View[] children = mChildren;        int flags = mGroupFlags;        if ((flags & FLAG_RUN_ANIMATION) != 0 && canAnimate()) {            final boolean cache = (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;            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);                    if (cache) {                        child.setDrawingCacheEnabled(true);                        if (buildCache) {                            child.buildDrawingCache(true);                        }                    }                }            }            final LayoutAnimationController controller = mLayoutAnimationController;            if (controller.willOverlap()) {                mGroupFlags |= FLAG_OPTIMIZE_INVALIDATE;            }            controller.start();            mGroupFlags &= ~FLAG_RUN_ANIMATION;            mGroupFlags &= ~FLAG_ANIMATION_DONE;            if (cache) {                mGroupFlags |= FLAG_CHILDREN_DRAWN_WITH_CACHE;            }            if (mAnimationListener != null) {                mAnimationListener.onAnimationStart(controller.getAnimation());            }        }        int clipSaveCount = 0;        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);        }        // We will draw our child's animation, let's reset the flag        mPrivateFlags &= ~PFLAG_DRAW_ANIMATION;        mGroupFlags &= ~FLAG_INVALIDATE_REQUIRED;        boolean more = false;        final long drawingTime = getDrawingTime();        if (usingRenderNodeProperties)            canvas.insertReorderBarrier();        // Only use the preordered list if not HW accelerated, since the HW        // pipeline will do the        // draw reordering internally        final ArrayList<View> preorderedList = usingRenderNodeProperties ? null                : buildOrderedChildList();        final boolean customOrder = preorderedList == null                && isChildrenDrawingOrderEnabled();        for (int i = 0; i < childrenCount; i++) {            int childIndex = customOrder ? getChildDrawingOrder(childrenCount,                    i) : i;            final View child = (preorderedList == null) ? children[childIndex]                    : preorderedList.get(childIndex);            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE                    || child.getAnimation() != null) {                more |= drawChild(canvas, child, drawingTime);            }        }        if (preorderedList != null)            preorderedList.clear();        // Draw any disappearing views that have animations        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);        }        // mGroupFlags might have been updated by drawChild()        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() {                public void run() {                    notifyAnimationListener();                }            };            post(end);        }    }

71行,开始遍历所有的子View,78行调用drawChild,开始绘制子View:

 protected boolean drawChild(Canvas canvas, View child, long drawingTime) {        return child.draw(canvas, this, drawingTime);    }

接着,又从从上往下,开始绘制,直到所有的View都绘制完成,整个绘制的流程如下:

更多相关文章

  1. android 广播 service
  2. 【Android】利用服务Service创建标题栏通知
  3. Android(安卓)Studio 下获取应用的数字签名MD5、SHA1方法
  4. Android(安卓)8.0 Navigationbar
  5. 不同Activity之间传递数据
  6. http请求No peer certificate的解决方法
  7. DataBinding 填坑总结
  8. Android部分手机拍照上传返回为空处理
  9. 基于ARouter的组件化开发

随机推荐

  1. Android(安卓)5.0 Lollipop 短彩信接收流
  2. android不在坑系列一:数据库框架的选择
  3. android之远程控制电脑播放ppt
  4. Android(安卓)用户界面---拖放(Drag and D
  5. 雷军:小米做Pad没难度 不做因Android市场
  6. 关于在Android上编写《热血传奇》的妄想
  7. 线程池.(Executors,ThreadPoolExecutor,B
  8. 超越iPhone和Android:开发者的5个新兴平台
  9. Android设计模式2--工厂方法模式
  10. android高级应用课程大纲