Pich Blog

关注移动开发,大数据,云计算,软件架构!

13.MeasureSpec到底是什么

概述

自定义控件中经常遇到MeasureSpec,那他到底是什么呢。我们来看看

翻译为“测量规格”或者是“测量说明”,也就是说他决定了View的测量过程。

他确定了一个View的大小和测试模式。

这个类是如何实现的

他其实是封装了一个32位的int值,高2位代表SpecMode,低30位代表了SpecSize。也就是测试模式,和测量带下。我们看看他的定义:

我这里删除了他的注释。他这里将他打包成一个int的好处是避免创建过多的对象。

同时他还提供了打包和解包方法。SpecMode和SpecSize都是一个int值。

三种测量模式

可以看到上面的源代码里面定义了三种测量模式。

UNSPECIFIED

父容器不对View有任何显示,要多大给多大,这种情况一般用于系统内部。

EXACTLY

父容器已经检测出View所需要的精确大小,这是时候View的最终大小就是SpecSize所指定的值,他对应于LayoutParams中的match_parent和具体的数值。

AT_MOST

父容器指定了可用大小SpecSize,view的尺寸不能超过他,具体多大还得看View的实现,他对应于LayoutParams中的wrap_content和具体的数值。

MeasureSpec和LayoutParams对应关系

上面说到系统内部是通过MeasureSpec对应View进行测量,但是我们还可以给View设置LayoutParams,所以在View的测量的时候还需要考虑LayoutParams,所以系统会将LayoutParams在父容器的约束下转成对应的MeasureSpec,然后在根据MeasureSpec测试View的宽高。

需要注意的MeasureSpec并不是唯一由LayoutParams决定,他需要看父容器。

定于顶层View(DecorView)和普通View的MeasureSpec转换不太一样:

普通View

他的MeasureSpec由父容器的MeasureSpec和自身的LayoutParams决定。

对于普通View,View的measure过程有ViewGroup传递过来的,我们看看ViewGroup的measureChildWithMargins方法:

可以看到在调用子元素的measure方法前,先通过getChildMeasureSpec方法创建了MeasureSpec。具体的我们在看一下getChildMeasureSpec方法:

上面的规则可以总结为下表:

DecorVeiw

他的MeasureSpec窗口尺寸和其自身的LayoutParams共同决定。

我们来看看DecorView:

的measureHierarchy方法可以看到他是这样生成MeasureSpec的:

他调用了getRootMeasureSpec来创建自己的MeasureSpec,然后调用performMeasure执行measure。在看看getRootMeasureSpec是如何工作的:

也就说说DecorView的measureSpec创建遵守了下面的规则:

  1. MATCH_PARENT模式,精确模式,大小就是窗口的大小
  2. WRAP_CONTENT,大小不定,但不能超过窗口大小
  3. 固定大小,也就是精确模式,大小就为LayoutParams中指定的大小
点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注