View的绘制流程分析之四 -- draw

来源:互联网 发布:中国的穆斯林问题 知乎 编辑:程序博客网 时间:2024/06/13 20:08

转载请注明出处:http://blog.csdn.net/crazy1235/article/details/72633392


draw - 绘制

将View绘制在屏幕上!

在ViewRootImpl.java的函数performTravesals() 方法体最后,就开始了绘制流程!

if (!cancelDraw && !newSurface) {            if (mPendingTransitions != null && mPendingTransitions.size() > 0) {                for (int i = 0; i < mPendingTransitions.size(); ++i) {                    mPendingTransitions.get(i).startChangingAnimations();                }                mPendingTransitions.clear();            }            performDraw();

performDraw()

private void performDraw() {        // ...        // 第一次绘制mFullRedrawNeeded = true, 表示全部绘制        final boolean fullRedrawNeeded = mFullRedrawNeeded;        mFullRedrawNeeded = false;        try {            draw(fullRedrawNeeded); // draw(true)        } finally {            mIsDrawing = false;            Trace.traceEnd(Trace.TRACE_TAG_VIEW);        }        // ...    }

方法内部调用 draw()

private void draw(boolean fullRedrawNeeded) {        // ...        if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {            // ...            } else {                // ...                if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)) {                    return;                }            }        }        // ...    }

drawSoftware()

private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,            boolean scalingRequired, Rect dirty) {        // ...        // 这里创建了canvas对象!        canvas = mSurface.lockCanvas(dirty);        try {            // ...            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 {                // ...            }        } finally {            // ...        }        return true;    }

这里才针对DecorView开始真正的绘制流程!

不管是ViewGroup还是View都是调用 View.draw(canvas)


View.java中draw(Canvas canvas)有这样一段注释:

        /*         * 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)         */

这段注释说明了draw() 绘制的流程步骤!

  • 绘制背景

  • 绘制自己的内容

  • 绘制子view

  • 绘制装饰


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) {            // 第三步,绘制自己的内容            if (!dirtyOpaque) onDraw(canvas);            // 第四步,绘制子view            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;        }        // ...    }

drawBackground(Canvas canvas)

/**     * Draws the background onto the specified canvas.     *     * @param canvas Canvas on which to draw the background     */    private void drawBackground(Canvas canvas) {        final Drawable background = mBackground;        if (background == null) { // 无背景直接return            return;        }        setBackgroundBounds();        // Attempt to use a display list if requested.        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;            }        }        final int scrollX = mScrollX;        final int scrollY = mScrollY;        if ((scrollX | scrollY) == 0) {            background.draw(canvas); // 绘制背景        } else { // 如果有scrollX,scrollY值,则需要先移动画布,在进行绘制,最后画布反向移动还原            canvas.translate(scrollX, scrollY);            background.draw(canvas); // 绘制背景            canvas.translate(-scrollX, -scrollY);        }    }

onDraw(Canvas canvas)

protected void onDraw(Canvas canvas) {    }

onDraw()函数在View中是一个空实现!不同的View实现类有不同的实现!


dispatchDraw(Canvas canvas)

ViewGroup.dispatchDraw()

@Override    protected void dispatchDraw(Canvas canvas) {        boolean usingRenderNodeProperties = canvas.isRecordingFor(mRenderNode);        final int childrenCount = mChildrenCount;        final View[] children = mChildren;        int flags = mGroupFlags;        // ...        // 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++) { // 遍历子View            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); // 调用drawChild()                }                transientIndex++;                if (transientIndex >= transientCount) {                    transientIndex = -1;                }            }            // ...        }        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;            }        }        // ...    }

方法内部遍历子view,调用drawChild()来绘制子view

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

这里又调用View的draw()方法。上面已经分析过!


onDrawForeground(Canvas canvas)

public void onDrawForeground(Canvas canvas) {        onDrawScrollIndicators(canvas);        onDrawScrollBars(canvas);        final Drawable foreground = mForegroundInfo != null ? mForegroundInfo.mDrawable : null;        if (foreground != null) { // forground不为空才绘制            if (mForegroundInfo.mBoundsChanged) {                mForegroundInfo.mBoundsChanged = false;                final Rect selfBounds = mForegroundInfo.mSelfBounds;                final Rect overlayBounds = mForegroundInfo.mOverlayBounds;                if (mForegroundInfo.mInsidePadding) { // 设置bound                    selfBounds.set(0, 0, getWidth(), getHeight());                } else {                    selfBounds.set(getPaddingLeft(), getPaddingTop(),                            getWidth() - getPaddingRight(), getHeight() - getPaddingBottom());                }                final int ld = getLayoutDirection();                Gravity.apply(mForegroundInfo.mGravity, foreground.getIntrinsicWidth(),                        foreground.getIntrinsicHeight(), selfBounds, overlayBounds, ld);                foreground.setBounds(overlayBounds);            }            foreground.draw(canvas); // 开始绘制        }    }

这里写图片描述


OVER!

原创粉丝点击