Android -View框架的measure机制

151 阅读3分钟

系统为什么要有measure过程

由于Android希望提供一个更优雅的GUI框架,所以提供了自适应的尺寸,也就是 wrap_content 和 match_parent 。

如果这些属性只允许设置固定的大小,那么每个View的尺寸在绘制的时候就已经确定了,所以可能都不需要measure过程。但是由于需要满足自适应尺寸的机制,所以需要一个measure过程。

measure过程都做了什么

在用自适应尺寸来定义View大小的时候,View的真实尺寸还不能确定。但是View尺寸最终需要映射到屏幕上的像素大小。

measure过程就是把各种尺寸值,经过计算,得到具体的像素值。

measure过程会遍历整棵View树,然后依次测量每个View真实的尺寸。具体是每个ViewGroup会向它内部的每个子View发送measure命令,然后由具体子View的onMeasure()来测量自己的尺寸。最后测量的结果保存在View的mMeasuredWidth和mMeasuredHeight中(保存的数据单位是像素)。

如何合理的测量一颗View树

系统在遍历完布局文件后,针对布局文件,在内存中生成对应的View树结构,这个时候,整棵View树种的所有View对象,都还没有具体的尺寸,因为measure过程最终是要确定每个View打的准确尺寸,也就是准确的像素值。但是刚开始的时候,View中layout_width和layout_height两个属性的值,都只是自适应的尺寸,也就是match_parent和wrap_content,这两个值在系统中为负数,所以系统不会把它们当成具体的尺寸值。所以当一个View需要把它内部的match_parent或者wrap_content转换成具体的像素值的时候,他需要知道两个信息。

1、针对于match_parent,父布局当前具体像素值是多少,因为match_parent就是子View想要和父布局一样大。

2、针对wrap_content,子View需要根据当前自己内部的content,算出一个合理的能包裹所有内容的最小值。但是如果这个最小值比当前父布局还大,那不行,父布局会告诉你,我只有这么大,你也不应该超过这个尺寸。

image.png

ViewGroup是如何向子View传递限制信息的

MeasureSpec类贯穿于整个measure过程,用来传递父布局对子View尺寸测量的约束信息。简单来说,该类就保存两类数据。

  1. 子View当前所在父布局的具体尺寸。
  2. 父布局对子View的限制类型。

限制类型又分为三种类型:

  1. UNSPECIFIED,不限定。意思就是,子View想要多大,我就可以给你多大,你放心大胆的measure吧,不用管其他的。也不用管我传递给你的尺寸值。(其实Android高版本中推荐,只要是这个模式,尺寸设置为0)

  2. EXACTLY,精确的。意思就是,根据我当前的状况,结合你指定的尺寸参数来考虑,你就应该是这个尺寸,具体大小在MeasureSpec的尺寸属性中,自己去查看吧,你也不要管你的content有多大了,就用这个尺寸吧。

  3. AT_MOST,最多的。意思就是,根据我当前的情况,结合你指定的尺寸参数来考虑,在不超过我给你限定的尺寸的前提下,你测量一个恰好能包裹你内容的尺寸就可以了。