绘制流程

161 阅读2分钟

通过测量确定了View成员变量mMeasuredWidth和mMeasuredHeight的值,通过布局确定了View相对于父View左上右下的值。当所有的View的大小和位置全部确定之后,我们就可以进行绘制了。

三大工作流程始于ViewRootImpl#performTraversals,在这个方法内部会分别调用performMeasure,performLayout,performDraw三个方法来分别完成测量,布局,绘制流程。那么我们现在先从performDraw方法看起,ViewRootImpl#performDraw

private void performDraw() {
    try {
        draw(fullRedrawNeeded);
    } finally {
        mIsDrawing = false;
        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
    }
}

上边方法调用ViewRootImpl中的drow方法,注意这里调用的是自己类中的draw方法。并传递了fullRedrawNeeded参数,而该参数由mFullRedrawNeeded成员变量获取,它的作用是判断是否需要重新绘制全部视图,如果是第一次绘制视图,那么显然应该绘制所以的视图,如果由于某些原因,导致了视图重绘,那么就没有必要绘制所有视图。继续看draw方法

private void draw(boolean fullRedrawNeeded) {

    //获取mDirty,该值表示需要重绘的区域
    final Rect dirty = mDirty;
    if (mSurfaceHolder != null) {
        // The app owns the surface, we won't draw.
        dirty.setEmpty();
        if (animating) {
            if (mScroller != null) {
                mScroller.abortAnimation();
            }
            disposeResizeBuffer();
        }
        return;
    }

    //第一次绘制流程,设置需要绘制所有视图
    if (fullRedrawNeeded) {
        mAttachInfo.mIgnoreDirtyState = true;
        dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
    }

    //然后把绘制区域和相关参数传递过去
    if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)) {
        return;
    }


}

我们继续看drawSofeware方法

private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
                             boolean scalingRequired, Rect dirty) {
    //锁定canvas区域,由dirty区域决定
    canvas = mSurface.lockCanvas(dirty);
    //正式开始绘制,这里的mView是DecorView
    mView.draw(canvas);

}

mView就是DecorView,也就是说从DecorView开始绘制,前面所做的一切工作都是准备工作,而现在则是正式开始绘制流程。和之前的逻辑差不多,这里分析的很好,回来用到在做分析