onMeasure
View的繪製流程是從ViewRoot(繼承Handler)的performTraversals中內部調用measure方法開始
measure() 方法接收widthMeasureSpec和heightMeasureSpec兩個參數,兩個參數由performTravelsals內部getRootMeasureSpec得到
MeasureSpec由specSize和SpecMode組成,SpecMode有三種類型:EXACTLY、AT_MOST以及不常用的UNSPECIFIED
measure方法是final的,其中的onMeasure纔可以重寫。真正執行測量的是onMeasure()方法,如果不重寫,默認會調用getDefaultSize獲取系統測量的默認大小,setMeasureDimension設置
注意:setMeasureDimension之後才能getMeasureWidth、getMeasureHeight
補充:ViewGroup定義了measureChildren遍歷子視圖-->逐個調用measureChild-->獲取各自的MeasureSpec,調用measure(childWidthMeasreSpec,childHeightSpec)
onLayout
measure過程結束後,VieRoot的performTraversals在measure()方法結束後繼續執行,通過調用VIew的layout()方法執行,layout()接收左上右下四個座標參數,代表在父視圖中的位置
layout方法首先調用setFrame()方法判斷視圖大小是否發生變化,是否需要重繪視圖,同時將接收的四個座標賦值給mLeft、mTop、mRight、mBottom,接着調用的onLayout方法;
View的onLayout方法是一個空方法,因爲確定視圖的佈局位置應該是由佈局完成,由父視圖決定子視圖的位置,然而ViewGroup的onLayout方法是一個抽象方法,像LInearLayout、RelativeLayout都是重寫了這個方法;
注意:getMeasureWidth和getWidth的區別:getMeasureWidth在measure過程結束後獲取,getWidth在layout過程結束後獲取;getMeasureWidth通過setMeasureDimension設置,getWidth通過視圖右邊的座標減去左邊的座標計算得到;
一般是一樣的值,如果在layout過程中不用measure()獲得設定的寬高,等於忽視measure過程的計算結構,會不一樣,這樣也沒有太大
onDraw
這裏才真正開始對視圖進行繪製,VIewRoot的代碼繼續執行創建畫布對象Canvas,調用View的draw()方法執行具體的繪製;
draw(Canvas canvas)首先獲取mBGDrawable對象繪製背景:這個對象就是從XML中通過background屬性設置的圖片或顏色
接着調用onDraw()方法繪製視圖內容:onDraw是個空方法,因爲每個視圖內容不同,一般交給子類實現:如TextView、ImageView都重寫onDraw()方法
接着調用dispatchDraw()對當前視圖的子視圖繪製:而VIew中的dispatchDraw方法又是一個空方法,ViewGroup的dispatchDraw()方法就會有具體的繪製代碼
最後onDrawScrollBars()繪製視圖的滾動條