繪製流程

稀飯_發表於2018-07-20

通過測量確定了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開始繪製,前面所做的一切工作都是準備工作,而現在則是正式開始繪製流程。和之前的邏輯差不多,這裡分析的很好,回來用到在做分析




相關文章