本文例子如下所示:

android:orientation="vertical"

android:layout_width="match_parent"

android:layout_height="wrap_content" >

android:layout_width="match_parent"

android:layout_height="wrap_content" />

android:layout_width="match_parent"

android:layout_height="20dp" />

过程

计算view大小的过程可以分为以下几个步骤:

确定view想要的size(LayoutParams)

确定parent view的情况(MeasureSpec)

在parent view的限制下,根据view的LayoutParams,确定view的大小

参数

LayoutParams

LayoutParams用于view表示想要的size的模式。有以下三种:

FILL_PARENT / MATCH_PARENT (-1)

view的size和parent view的size一样大

WRAP_CONTENT(-2)

view的size仅包裹其内容即可

指定的值(>0)

view的size为指定的size大小

MeasureSpec

MeasureSpec表示当前view的“约束”(在onMeasure中传入)。约束含模式mode和数值size,当前view根据mode来决定如何看待其中的size。

mode

mode有三种,如下所示:

UNSPECIFIED

对当前view的size没有约束

EXACTLY

当前view的bounds(可以理解成“可以使用的范围”)为确定的size,也可以理解成parent view希望当前view(有强制的意味)使用给定的size

AT_MOST

当前view的大小不可超过指定的size

可以利用MeasureSpec的getMode取出具体值.

size

size为8个byte的int值,mode放在前2个bit中。这里可以利用MeasureSpec的getSize取出size的具体值。

onMeasure过程

view通过onMeasure确定自己的大小。确定自己的大小时,需要的东西有:

约束MeasureSpec

自己的LayoutParams

如果有child view,那么需要获取child view的大小

最终确定当前view的size分别为:

measureWidth

measureHeight

single view

以前面例子中的TextView为例,其onMeasure中传入的MeasureSpec为:

Width

mode:EXACTLY size:parentContentWidth(LinearLayout的宽-padding)

Height

mode:AT_MOST size:parentContentHeight(LinearLayout的高-padding)

注:这里先不解释为什么MeasureSpec是这样的。

TextView的LayoutParams为:

Width

MATCH_PARENT

Height

WRAP_CONTENT

然后TextView根据约束和LayoutParams确定自己的大小,包括但不限于以下过程:

设置宽度为parentContentWidth,考虑margin确定字符可用范围

根据字符高度和字体设置(根据是否超过parentContentWidth确定是否换行)等计算字符所占的高度(没有限制)。

设置measureWidth和measureHeight

ViewGroup

以前面例子中的LinearLayout为例,假设该LinearLayout为Activity中的root layout其onMeasure中传入的MeasureSpec为:

Width

mode:EXACTLY size:parentContentWidth(LinearLayout的parent view的宽-padding)

Height

mode:AT_MOST size:parentContentHeight(LinearLayout的parent view的高-padding)

RelativeLayout的LayoutParams为:

Width

MATCH_PARENT

Height

WRAP_CONTENT

Orientation

vertical

然后LinearLayout根据约束和LayoutParams确定自己的大小,包括但不限于以下过程:

确定child view的排列方式

确定TextView的size

确定ImageView的size

根据自身的设置,设置measureWidth和measureHeight

要确定child view的size,就要调用child view的onMeasure,传入合适的MeasureSpec,表明parent view对child的约束。

根据parent view的不同module和child view的不同LayoutParams,有如下规则:

当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.

当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.

当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为例:

LinearLayout的width mode为EXACTLY,TextView的width layout param为MATCH_PARENT

LinearLayout的height mode为AT_MOST,TextView的height layout param为WRAP_CONTENT

所以TextView的onMeasure会被传入:

Width

mode:EXACTLY size:parentContentWidth(LinearLayout的宽-padding)

Height

mode:AT_MOST size:parentContentHeight(LinearLayout的高-padding)

TextView可以根据上述约束计算自己的大小。ImageView同理。最后LinearLayout根据ImageView和TextView的大小计算自己的大小。注意这里没有weight的设置,所以onMeasure只运行一次。

如上述有错,请留言告知。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐