整個View樹的繪圖流程是在ViewRoot.java類的performTraversals()函數展開的,該函數做的執行過程可簡單概況為根據之前
設置的狀態,判斷是否需要重新計算視圖大小(measure)、是否重新需要安置視圖的位置(layout)、以及是否需要重繪(draw),其框架過程如下:
接下來溫習一下整個View樹的結構,對每個具體View對象的操作,其實就是個遞歸的實現。
本文相關代碼下載
免費下載地址在 http://linux.linuxidc.com/
用戶名與密碼都是www.linuxidc.com
具體下載目錄在 /2012年資料/1月/9日/Android中View繪制流程以及invalidate()等相關方法分析/
流程一: mesarue()過程
主要作用:為整個View樹計算實際的大小,即設置實際的高(對應屬性:mMeasuredHeight)和寬(對應屬性:mMeasureWidth),
每個View的控件的實際寬高都是由父視圖和本身視圖決定的。
具體的調用鏈如下:
ViewRoot根對象地屬性mView(其類型一般為ViewGroup類型)調用measure()方法去計算View樹的大小,回調View/ViewGroup
對象的onMeasure()方法,該方法實現的功能如下:
1、設置本View視圖的最終大小,該功能的實現通過調用setMeasuredDimension()方法去設置實際的高(對應屬性:
mMeasuredHeight)和寬(對應屬性:mMeasureWidth) ;
2 、如果該View對象是個ViewGroup類型,需要重寫該onMeasure()方法,對其子視圖進行遍歷的measure()過程。
2.1 對每個子視圖的measure()過程,是通過調用父類ViewGroup.java類裡的measureChildWithMargins()方法去實現,
該方法內部只是簡單地調用了View對象的measure()方法。(由於measureChildWithMargins()方法只是一個過渡層,更簡單
的做法是直接調用View對象的measure()方法)
整個measure調用流程就是個樹形的遞歸過程
measure函數原型為 View.java 該函數不能被重載
- public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
- //....
-
- //回調onMeasure()方法
- onMeasure(widthMeasureSpec, heightMeasureSpec);
-
- //more
- }
為了大家更好的理解,采用“二B程序員”的方式利用偽代碼描述該measure流程
- // measure()過程 ViewRoot.java
- // 發起measure()的"發號者"在ViewRoot.java裡的performTraversals()方法, mView.measure()
- private void performTraversals(){
- //...
-
- View mView ;
- mView.measure(h,l) ;
-
- //....
- }
-
- //回調View視圖裡的onMeasure過程
- private void onMeasure(int height , int width){
- //設置該view的實際寬(mMeasuredWidth)高(mMeasuredHeight)
- //1、該方法必須在onMeasure調用,否者報異常。
- setMeasuredDimension(h , l) ;
-
- //2、如果該View是ViewGroup類型,則對它的每個子View進行measure()過程
- int childCount = getChildCount() ;
-
- for(int i=0 ;i<childCount ;i++){
- //2.1、獲得每個子View對象引用
- View child = getChildAt(i) ;
-
- //整個measure()過程就是個遞歸過程
- //該方法只是一個過濾器,最後會調用measure()過程 ;或者 measureChild(child , h, i)方法都
- measureChildWithMargins(child , h, i) ;
-
- //其實,對於我們自己寫的應用來說,最好的辦法是去掉框架裡的該方法,直接調用view.measure(),如下:
- //child.measure(h, l)
- }
- }
-
- //該方法具體實現在ViewGroup.java裡 。
- protected void measureChildWithMargins(View v, int height , int width){
- v.measure(h,l)
- }