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

Android中View的繪制過程

View可以看成一個樹形結構,父控件是父節點,子控件是子節點。View的繪制過程就是遍歷這棵樹。

View的繪制有三步:

  1. measure:測量View的Width和Height,
  2. layout:布局View(left,right,top,bottom),指定View和手機屏幕的上下左右的距離。
  3. draw:繪圖

以上的步驟必須按照順序來。(順便說一下,以上三個步驟發生在View的構造方法之後。)

一、measure

measure是繪制視圖的第一步,因為只有知道的View的大小(Width和Height)才能繪圖。

我們在編寫layout的xml文件的時候,會遇到layout_width和layout_height兩個屬性,對於這兩個屬性我們有三個選擇:fill_parent、wrap_content和具體值,measure就是用來處理fill_parent、wrap_content兩個屬性的,在繪圖的時候,要知道具體的值,所以要計算fill_parent、wrap_content的具體值。

下面是幾個重要的函數和參數:

  1. public final void measure(int widthMeasureSpec, int heightMeasureSpec)
  2. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
  3. protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec)
  4. protected void measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec)
  5. protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed)

前兩個方法是View類裡面的方法,後三個方法是ViewGroup類裡面的方法。

先來看看measure的源碼:

  1. /** 
  2.      * <p> 
  3.      * This is called to find out how big a view should be. The parent 
  4.      * supplies constraint information in the width and height parameters. 
  5.      * </p> 
  6.      * 
  7.      * <p> 
  8.      * The actual mesurement work of a view is performed in 
  9.      * {@link #onMeasure(int, int)}, called by this method. Therefore, only 
  10.      * {@link #onMeasure(int, int)} can and must be overriden by subclasses. 
  11.      * </p> 
  12.      * 
  13.      * 
  14.      * @param widthMeasureSpec Horizontal space requirements as imposed by the 
  15.      *        parent 
  16.      * @param heightMeasureSpec Vertical space requirements as imposed by the 
  17.      *        parent 
  18.      * 
  19.      * @see #onMeasure(int, int) 
  20.      */  
  21.     public final void measure(int widthMeasureSpec, int heightMeasureSpec) {  
  22.         if ((mPrivateFlags & FORCE_LAYOUT) == FORCE_LAYOUT ||  
  23.                 widthMeasureSpec != mOldWidthMeasureSpec ||  
  24.                 heightMeasureSpec != mOldHeightMeasureSpec) {  
  25.   
  26.             // first clears the measured dimension flag   
  27.             mPrivateFlags &= ~MEASURED_DIMENSION_SET;  
  28.   
  29.             if (ViewDebug.TRACE_HIERARCHY) {  
  30.                 ViewDebug.trace(this, ViewDebug.HierarchyTraceType.ON_MEASURE);  
  31.             }  
  32.   
  33.             // measure ourselves, this should set the measured dimension flag back   
  34.             onMeasure(widthMeasureSpec, heightMeasureSpec);  
  35.   
  36.             // flag not set, setMeasuredDimension() was not invoked, we raise   
  37.             // an exception to warn the developer   
  38.             if ((mPrivateFlags & MEASURED_DIMENSION_SET) != MEASURED_DIMENSION_SET) {  
  39.                 throw new IllegalStateException("onMeasure() did not set the"  
  40.                         + " measured dimension by calling"  
  41.                         + " setMeasuredDimension()");  
  42.             }  
  43.   
  44.             mPrivateFlags |= LAYOUT_REQUIRED;  
  45.         }  
  46.   
  47.         mOldWidthMeasureSpec = widthMeasureSpec;  
  48.         mOldHeightMeasureSpec = heightMeasureSpec;  
  49.     }  
measure方法是final類型的,所以不能被繼承,不能被復寫。而measure方法裡面調用了onMeasure方法,onMeasure方法可以被繼承,可以被復寫。下面是onMeasure源碼:
  1. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  2.         setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),  
  3.                 getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));  
  4.     }  
onMeasure默認的實現僅僅調用了setMeasuredDimension,setMeasuredDimension函數是一個很關鍵的函數,它對View的成員變量mMeasuredWidth和mMeasuredHeight變量賦值,而measure的主要目的就是對View樹中的每個View的mMeasuredWidth和mMeasuredHeight進行賦值,一旦這兩個變量被賦值,則意味著該View的測量工作結束。

setMeasuredDimension源碼如下:

  1. protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {  
  2.     mMeasuredWidth = measuredWidth;  
  3.     mMeasuredHeight = measuredHeight;  
  4.   
  5.     mPrivateFlags |= MEASURED_DIMENSION_SET;  
  6. }  
再來看下MeasureSpec這個類,MeasureSpec參數的值為int型,分為高32位和低16為,高32位保存的是specMode,低16位表示specSize,specMode分三種:

  1. MeasureSpec.UNSPECIFIED:父視圖不對子視圖施加任何限制,子視圖可以得到任意想要的大小
  2. MeasureSpec.EXACTLY:父視圖希望子視圖的大小是specSize中指定的大小
  3. MeasureSpec.AT_MOST:子視圖的大小最多是specSize中的大小

以上施加的限制只是父視圖“希望”子視圖的大小按MeasureSpec中描述的那樣,但是子視圖的具體大小取決於多方面的。

Copyright © Linux教程網 All Rights Reserved