1.viewroot.java中,應用程式主動調用invalidate或setEnable等調用間接調用invalidate,invalidate中會遍曆view樹,請求重繪需要繪製的地區
invalidate主要是確定需要重繪的地區,然後調用scheduleTraversals發起重繪請求,scheduleTraversals最終調用performTraversals遍曆view tree進行重繪
2.measure:performTraversals首先會遍曆調用view樹中所有view的measure方法來測量出view的大小
從viewRoot的mView開始measure,這個mView是一個DecorView對象(繼承自FrameLayout,屬於ViewGroup),ViewGroup中沒有覆寫measure函數,事實上measure是一個final方法,無法覆寫,所以所有view子類的measure都是調用view的measure
public final void measue(int widthMeasureSpec, int heightMeasureSpec);
viewRoot在measure中根據螢幕大小和DecorView的布局(FrameLayout)確定widthMeasureSpec和heightMeasureSpec來作為參數傳入measue,measue裡回調OnMeasure,view的OnMeasure對傳入的參數通過一定的演算法算出準確的長和寬,至此,DecView本身的大小就measure完了,而DecView中的子控制項如何measure呢?
measure是final的,但是其回調的OnMeasure是virtual的,事實上,view和viewGroup的大小都是在OnMeasure中計算出來的,預設的OnMeasure只是計算出本view或viewGroup的大小,如果是自定viewgroup,我們可以重寫onmeasure,把viewgroup的大小寫死(這樣布局xml裡寫的match_parent或者wrap_content就不起作用了),當然這樣做是不建議的,通常viewGroup的子類都會重寫Onmeasure,在裡面除了調用view的onmeasure確定自己的大小外,也確定所有子view的大小(如果子view是viewgroup,再繼續這個過程),那麼怎麼確定子view的大小呢,跟viewroot中確定decView類似,先根據父viewGroup的大小和布局確定傳給子view的measure函數的參數widthMeasureSpec和heightMeasureSpec,子view調用measureFunction Compute出子view的最終大小(這個過程封裝在viewgroup的MeasureChildren中了。
自訂viewGroup的子類時,一般要覆寫OnMeasure方法,這這個Onmeasure方法裡,可以調用ViewGroup的MeasureChildren,也可以自己直接調用所有子view的Measure(MeasureChildren不是自動調用的,只是提供給使用者需要時手動調用的,很多android應用程式層的viewGroup子類都調用它來對子view做measure)
在沒有measure之前,view是沒有大小的,getMeasuredWidth、getMeasuredHeight()都是0,沒有layout之前,getWidth和getHeight都是0,在layout中還可以重新確定控制項大小,所以getwith和getHeight得到的值和getMeasuredWidth、getMeasuredHeight()得到的值不一定一樣,前者是真實的繪製在螢幕上的大小,後者是measure執行完後的測量大小,當然,預設情況下,layout使用的是measure中測算的大小,除非覆寫了OnLayout,在其中重定義了大小
所以多viewGroup子類而言,OnMeasure不是必須的,因為最終子view的大小和位置是layout決定的,onlayout才是必須的。
3. layout:measure完成後就會調用layout,同樣是遍曆view tree進行layout,layout方法也是final的:
public void layout(int left, int top, int right, int bottom)
自訂viewgroup放入布局xml中,父布局會調用其measure和layout,所以不用管,但是其子view都是靠自己measure和layout的,子view(非viewgroup)的Onmeasure和onlayout只是被父viewgroup調用預設的方法即可,無須重寫,子viewgroup要重寫Onmeasure和onlayout,為其下面的所有子view調用measure和layout(Onmeasure可選,onlayout必須)
viewroot根據前面的measure得到的MeasureWith和MeasureHeight調用DecorView的layout(0,0,MeasureWith,MeasureHeight),DecorView重寫onlayout,在其中調用所有子view的layout,子view如果是viewgroup,則此子view再重寫onlayout,以此類推。
layout中主要是確定其子view的位置和大小(大小可以用measure得到的大小,也可以自己再定義大小),以linearlayout為例,如果是垂直布局,則每layout一個子view,把下一個子view的top加上上一個view的高度,如果是自訂的viewgroup,則根據自己設計的布局需要來確定子view的layout位置,比如可以設計一個按長度適應螢幕自動換行的viewgroup
4.draw:同樣是遍曆view
tree調用所有view的draw,draw的大小和位置已經由measure和layout確定好了