博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android源码解析:UI绘制流程之控件绘制
阅读量:5968 次
发布时间:2019-06-19

本文共 17803 字,大约阅读时间需要 59 分钟。

带着问题看源码

再接再厉,我们来分析UI绘制流程最后一步绘制流程

入口ViewRootImpl.performDraw()方法

private void performDraw() {        //...        try {            draw(fullRedrawNeeded);           } finally {            mIsDrawing = false;            Trace.traceEnd(Trace.TRACE_TAG_VIEW);        }        //...    }    //调用了draw()方法,参数表示是否需要重新绘制全部视图    private void draw(boolean fullRedrawNeeded) {        Surface surface = mSurface;        //...        //控件重绘        final Rect dirty = mDirty;        if (mSurfaceHolder != null) {            // The app owns the surface, we won't draw.            dirty.setEmpty();            if (animating && mScroller != null) {                mScroller.abortAnimation();            }            return;        }        //fullRedrawNeeded为true,表示需要绘制整个区域        if (fullRedrawNeeded) {            mAttachInfo.mIgnoreDirtyState = true;            dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));        }        mAttachInfo.mTreeObserver.dispatchOnDraw();        //...                if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)) {                    return;                }            }    }    //最后会调用drawSoftware()复制代码

ViewRootImpl.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) {            mLayoutRequested = true; // ask wm for a new surface next time.            return false;        }        try {            //在画之前清除alpha通道,以便子控件重新组合其图纸上的透明背景            if (!canvas.isOpaque() || yoff != 0 || xoff != 0) {                canvas.drawColor(0, PorterDuff.Mode.CLEAR);            }            dirty.setEmpty();            mIsAnimating = false;            mView.mPrivateFlags |= View.PFLAG_DRAWN;            if (DEBUG_DRAW) {                Context cxt = mView.getContext();            }            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(mTag, "Could not unlock surface", e);                mLayoutRequested = true; // ask wm for a new surface next time.                //noinspection ReturnInsideFinallyBlock                return false;            }            if (LOCAL_LOGV) {                Log.v(mTag, "Surface " + surface + " unlockCanvasAndPost");            }        }        return true;    }复制代码

最后调用了View.draw()方法

@CallSuper    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()方法主要流程为:        //1、对View的背景进行绘制        //2、保存当前的图层信息        //3、绘制View的内容        //4、对View的子View进行绘制(如果有子View)        //5、绘制View的褪色的边缘,类似于阴影效果        //6、绘制View的装饰        // Step 1, draw the background, if needed        int saveCount;        if (!dirtyOpaque) { //判断View的背景是否是透明的?            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);            drawAutofilledHighlight(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);            // Step 7, draw the default focus highlight            drawDefaultFocusHighlight(canvas);            if (debugDraw()) {                debugDrawFocus(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);        drawAutofilledHighlight(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);        if (debugDraw()) {            debugDrawFocus(canvas);        }    }复制代码

画背景:调用了Drawable.draw(canves)方法

private void drawBackground(Canvas canvas) {        final Drawable background = mBackground;        if (background == null) {            return;        }        //设置背景区域大小        setBackgroundBounds();        // Attempt to use a display list if requested.        if (canvas.isHardwareAccelerated() && mAttachInfo != null                && mAttachInfo.mThreadedRenderer != 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 {            canvas.translate(scrollX, scrollY);            background.draw(canvas);            canvas.translate(-scrollX, -scrollY);        }    }复制代码

绘制子View

@Override    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 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;        final boolean clipToPadding = (flags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK;        if (clipToPadding) {            clipSaveCount = canvas.save(Canvas.CLIP_SAVE_FLAG);            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();        final int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();        int transientIndex = transientCount != 0 ? 0 : -1;        // Only use the preordered list if not HW accelerated, since the HW pipeline will do the        // draw reordering internally        final ArrayList
preorderedList = usingRenderNodeProperties ? null : buildOrderedChildList(); final boolean customOrder = preorderedList == null && isChildrenDrawingOrderEnabled(); for (int i = 0; i < childrenCount; i++) { 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; } } final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder); final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex); if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) { more |= drawChild(canvas, child, drawingTime); } } 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(); // Draw any disappearing views that have animations if (mDisappearingChildren != null) { final ArrayList
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); //绘制子View } } 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() { @Override public void run() { notifyAnimationListener(); } }; post(end); } }最后调用子View的draw()方法 protected boolean drawChild(Canvas canvas, View child, long drawingTime) { return child.draw(canvas, this, drawingTime); }复制代码

转载地址:http://anhax.baihongyu.com/

你可能感兴趣的文章
★核心关注点_《信息系统项目管理师考试考点分析与真题详解》
查看>>
卢松松:如何复制暴利产品
查看>>
Google Glass是工具不是玩具
查看>>
如何寻找高质量流量日入三百+
查看>>
f_bfree和f_bavail的区别
查看>>
Tegra3 vSMP架构Android运行时CPU热插拔及高低功耗CPU切换
查看>>
风雨飘摇中的HP会分拆Arcsight业务吗?
查看>>
技术者的好奇心和惯性
查看>>
Web前端开发必备:《Jquery实战》第3版 介绍
查看>>
为AD用户启用或禁用OCS 2007 R2帐户
查看>>
JNDI数据源的连接属性
查看>>
.NET重构—单元测试重构
查看>>
linux route命令深入浅出与实战案例精讲
查看>>
Azure Remoteapp 使用指南
查看>>
【翻译】Ext JS最新技巧——2014-8-13
查看>>
Powershell批量修改用户的UPN后缀
查看>>
Exchange Server 2016管理系列课件53.DAG管理之设置滞后数据库副本
查看>>
cocos2d-x学习笔记16:记录存储1:CCUserDefault
查看>>
创业做什么好?先学习精英式创业从平庸到卓越
查看>>
降低网站跳出率的六个方法(亲身使用)
查看>>