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