歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Android中View繪制流程以及invalidate()等相關方法分析

整個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 該函數不能被重載

 
  1.     public final void measure(int widthMeasureSpec, int heightMeasureSpec) {  
  2.             //....   
  3.           
  4.             //回調onMeasure()方法     
  5.             onMeasure(widthMeasureSpec, heightMeasureSpec);  
  6.              
  7.             //more   
  8.     }  

 

為了大家更好的理解,采用“二B程序員”的方式利用偽代碼描述該measure流程       

 
  1. // measure()過程  ViewRoot.java   
  2.    // 發起measure()的"發號者"在ViewRoot.java裡的performTraversals()方法, mView.measure()   
  3.    private void  performTraversals(){  
  4.     //...   
  5.       
  6.     View mView  ;  
  7.     mView.measure(h,l) ;  
  8.       
  9.     //....   
  10.    }  
  11.   
  12.   //回調View視圖裡的onMeasure過程   
  13.   private void onMeasure(int height , int width){  
  14.    //設置該view的實際寬(mMeasuredWidth)高(mMeasuredHeight)   
  15.    //1、該方法必須在onMeasure調用,否者報異常。   
  16.    setMeasuredDimension(h , l) ;  
  17.      
  18.    //2、如果該View是ViewGroup類型,則對它的每個子View進行measure()過程   
  19.    int childCount = getChildCount() ;  
  20.      
  21.    for(int i=0 ;i<childCount ;i++){  
  22.        //2.1、獲得每個子View對象引用   
  23.        View child = getChildAt(i) ;  
  24.          
  25.        //整個measure()過程就是個遞歸過程   
  26.        //該方法只是一個過濾器,最後會調用measure()過程 ;或者 measureChild(child , h, i)方法都   
  27.        measureChildWithMargins(child , h, i) ;   
  28.          
  29.        //其實,對於我們自己寫的應用來說,最好的辦法是去掉框架裡的該方法,直接調用view.measure(),如下:   
  30.        //child.measure(h, l)   
  31.    }  
  32.   }  
  33.     
  34.   //該方法具體實現在ViewGroup.java裡 。   
  35.   protected  void measureChildWithMargins(View v, int height , int width){  
  36.    v.measure(h,l)     
  37.   } 
Copyright © Linux教程網 All Rights Reserved