原文連結:https://www.jianshu.com/p/5a71014e7b1b
一、啟動:每個Activity 均會建立一個 PhoneWindow對象,是Activity和整個View系統互動的接口,每個Window都對應着一個View和一個ViewRootImpl,Window和View通過ViewRootImpl來建立聯系,對于Activity來說,ViewRootImpl是連接配接WindowManager和DecorView的紐帶,繪制的入口是由ViewRootImpl的performTraversals方法來發起Measure,Layout,Draw等流程的。
二、Measure過程:
1、MeasureSpec 的了解
是view的一個大小和模式的組合,
- MeasureSpec中的值是一個整型(32位)将size和mode打包成一個Int型,其中高兩位是mode,後面30位存的是size,是為了減少對象的配置設定開支。MeasureSpec 類似于下圖,隻不過這邊用的是十進制的數,而MeasureSpec 是二進制存儲的。
- MesureSpec三種模式
UPSPECIFIED : 父容器對于子容器沒有任何限制,子容器想要多大就多大
EXACTLY: 父容器已經為子容器設定了尺寸,子容器應當服從這些邊界,不論子容器想要多大的空間。
AT_MOST:子容器可以是聲明大小内的任意大小
父View的measure的過程會先測量子View,等子View測量結果出來後,再來測量自己,上面的measureChildWithMargins就是用來測量某個子View的,通過父view的measurespec的model确定子view的resultmodel和resultsize;
- 如果父View的MeasureSpec 是EXACTLY,說明父View的大小是确切的,(确切的意思很好了解,如果一個View的MeasureSpec 是EXACTLY,那麼它的size 是多大,最後展示到螢幕就一定是那麼大)。
- 如果父View的MeasureSpec 是AT_MOST,說明父View的大小是不确定,最大的大小是MeasureSpec 的size值,不能超過這個值。
- 如果父View的MeasureSpec 是UNSPECIFIED(未指定),表示沒有任何束縛和限制,不像AT_MOST表示最大隻能多大,不也像EXACTLY表示父View确定的大小,子View可以得到任意想要的大小,不受限制
ViewGroup的Measure過程
ViewGroup并沒有實作onMeasure,他會根據具體實作的onMeasure來measure所有子view的寬高。
三、layout
1.performTraversals 方法執行完mView.measure 計算出mMeasuredXXX後就開始執行layout 函數來确定View具體放在哪個位置,我們計算出來的View目前隻知道view矩陣的大小,具體這個矩陣放在哪裡,這就是layout 的工作了。 2.如果目前ViewGroup未添加LayoutTransition動畫,或者LayoutTransition動畫此刻并未運作,那麼調用super.layout(l, t, r, b),繼而調用到ViewGroup中的onLayout,否則将mLayoutSuppressed設定為true,等待動畫完成時再調用requestLayout()。 3.然後調用setFrame(l, t, r, b) 可以了解為給mLeft 、mTop、mRight、mBottom指派 4.回調onLayout,對于View來說,onLayout隻是一個空實作,對于viewgroup來說,onLayout是一個抽象方法,繼承viewgroup需實作onLayout,一般是周遊子view然後調用子view的layout方法
四、draw
performTraversals 方法的下一步就是mView.draw(canvas); 因為View的draw 方法一般不去重寫,官網文檔也建議不要去重寫draw 方法
public void 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)
*/
// Step 1, draw the background, if needed
...
background.draw(canvas);
...
// skip step 2 & 5 if possible (common case)
...
// Step 2, save the canvas' layers
...
if (solidColor == ) {
final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;
if (drawTop) {
canvas.saveLayer(left, top, right, top + length, null, flags);
}
...
// 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
if (drawTop) {
matrix.setScale(, fadeHeight * topFadeStrength);
matrix.postTranslate(left, top);
fade.setLocalMatrix(matrix);
canvas.drawRect(left, top, right, top + length, p);
}
...
// Step 6, draw decorations (scrollbars)
onDrawScrollBars(canvas);
}
1、第一步:背景繪制
2、第三步,對View的内容進行繪制。
3、第4步 對目前View的所有子View進行繪制(dispatchDraw)
4、第6步 對View的滾動條進行繪制