[Android] 如何計算View的Size

** 注:本文參考連接How Android caculates view sizeandroid

本文例子以下所示:ide

<LinearLayout
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="20dp" />

</LinearLayout>

過程

計算view大小的過程能夠分爲如下幾個步驟:post

  1. 肯定view想要的size(LayoutParams)
  2. 肯定parent view的狀況(MeasureSpec)
  3. 在parent view的限制下,根據view的LayoutParams,肯定view的大小

參數

LayoutParams

LayoutParams用於view表示想要的size的模式。有如下三種:字體

  1. FILL_PARENT / MATCH_PARENT (-1)
    view的size和parent view的size同樣大
  2. WRAP_CONTENT(-2)
    view的size僅包裹其內容便可
  3. 指定的值(>0)
    view的size爲指定的size大小

MeasureSpec

MeasureSpec表示當前view的「約束」(在onMeasure中傳入)。約束含模式mode和數值size,當前view根據mode來決定如何看待其中的size。.net

mode

mode有三種,以下所示:code

  1. UNSPECIFIED
    對當前view的size沒有約束
  2. EXACTLY
    當前view的bounds(能夠理解成「可使用的範圍」)爲肯定的size,也能夠理解成parent view但願當前view(有強制的意味)使用給定的size
  3. AT_MOST
    當前view的大小不可超過指定的size

能夠利用MeasureSpec的getMode取出具體值.ci

size

size爲8個byte的int值,mode放在前2個bit中。這裏能夠利用MeasureSpec的getSize取出size的具體值。get

onMeasure過程

view經過onMeasure肯定本身的大小。肯定本身的大小時,須要的東西有:it

  1. 約束MeasureSpec
  2. 本身的LayoutParams
  3. 若是有child view,那麼須要獲取child view的大小

最終肯定當前view的size分別爲:io

  1. measureWidth
  2. measureHeight

single view

之前面例子中的TextView爲例,其onMeasure中傳入的MeasureSpec爲:

  1. Width
    mode:EXACTLY size:parentContentWidth(LinearLayout的寬-padding)
  2. Height
    mode:AT_MOST size:parentContentHeight(LinearLayout的高-padding)

注:這裏先不解釋爲何MeasureSpec是這樣的。

TextView的LayoutParams爲:

  1. Width
    MATCH_PARENT
  2. Height
    WRAP_CONTENT

而後TextView根據約束和LayoutParams肯定本身的大小,包括但不限於如下過程:

  1. 設置寬度爲parentContentWidth,考慮margin肯定字符可用範圍
  2. 根據字符高度和字體設置(根據是否超過parentContentWidth肯定是否換行)等計算字符所佔的高度(沒有限制)。
  3. 設置measureWidth和measureHeight

ViewGroup

之前面例子中的LinearLayout爲例,假設該LinearLayout爲Activity中的root layout其onMeasure中傳入的MeasureSpec爲:

  1. Width
    mode:EXACTLY size:parentContentWidth(LinearLayout的parent view的寬-padding)
  2. Height
    mode:AT_MOST size:parentContentHeight(LinearLayout的parent view的高-padding)

RelativeLayout的LayoutParams爲:

  1. Width
    MATCH_PARENT
  2. Height
    WRAP_CONTENT
  3. Orientation
    vertical

而後LinearLayout根據約束和LayoutParams肯定本身的大小,包括但不限於如下過程:

  1. 肯定child view的排列方式
  2. 肯定TextView的size
  3. 肯定ImageView的size
  4. 根據自身的設置,設置measureWidth和measureHeight

要肯定child view的size,就要調用child view的onMeasure,傳入合適的MeasureSpec,代表parent view對child的約束。

根據parent view的不一樣module和child view的不一樣LayoutParams,有以下規則:

  1. 當parent view的mode是EXACTLY時:

    child layout mode size
    exact size EXACTLY childSize Child wants a specific size.
    MATCH_PARENT EXACTLY parentContentSize Child wants to be parent's size.
    WRAP_CONTENT AT_MOST parentContentSize Child wants to determine its own size. It can not be bigger than parent.
  2. 當parent view的mode是AT_MOST時:

    child layout mode size
    exact size EXACTLY childSize Child wants a specific size
    MATCH_PARENT AT_MOST parentContentSize Child wants to be parent's size, but parent's size is not fixed. Constrain child to not be bigger than parent.
    WRAP_CONTENT AT_MOST parentContentSize Child wants to determine its own size, but it can not be bigger than parent.
  3. 當parent view的mode是UNSPECIFIED時:

    child layout mode size
    exact size EXACTLY childSize Child wants a specific size.
    MATCH_PARENT UNSPECIFIED can not decide yet Child wants to be parent's size. Child will decide its own size later.
    WRAP_CONTENT UNSPECIFIED can not decide yet Child wants to be its own size. Child will decide its own size later.

以例子中的TextView爲例:

  1. LinearLayout的width mode爲EXACTLY,TextView的width layout param爲MATCH_PARENT
  2. LinearLayout的height mode爲AT_MOST,TextView的height layout param爲WRAP_CONTENT

因此TextView的onMeasure會被傳入:

  1. Width
    mode:EXACTLY size:parentContentWidth(LinearLayout的寬-padding)
  2. Height
    mode:AT_MOST size:parentContentHeight(LinearLayout的高-padding)

TextView能夠根據上述約束計算本身的大小。ImageView同理。最後LinearLayout根據ImageView和TextView的大小計算本身的大小。注意這裏沒有weight的設置,因此onMeasure只運行一次。

如上述有錯,請留言告知。

相關文章
相關標籤/搜索