在分析view的measure过程之前,有必要看看什么是measureSpec,因为它在view的measure流程中经常出现,比较重要,不知道的童鞋可能会感觉这是啥玩意儿,好高大上阿。。。其实看过之后会发现measureSpec并不难,下面开始----
一、MeasureSpec简介
MeasureSpec代表一个32位的int值,这个从类的常量中就可以看出来,它是View的内部类,如下:
public static class MeasureSpec {
private static final int MODE_SHIFT = 30;
private static final int MODE_MASK = 0x3 << MODE_SHIFT;
/**
* 父元素不限制子元素,子元素想要多大就多大
*/
public static final int UNSPECIFIED = 0 << MODE_SHIFT;
/**
* 精确:子元素会被给予一个确定的值,对应LayoutParams中的Match_parent和具体的数值
*/
public static final int EXACTLY = 1 << MODE_SHIFT;
/**
* 不大于:父元素提供一个可用的值,子元素不能超过这个值,对应LayoutParams中的wrap_content
*/
public static final int AT_MOST = 2 << MODE_SHIFT;
public static int makeMeasureSpec(int size, int mode) {
if (sUseBrokenMakeMeasureSpec) {
return size + mode;
} else {
return (size & ~MODE_MASK) | (mode & MODE_MASK);
}
}
public static int getMode(int measureSpec) {
return (measureSpec & MODE_MASK);
}
*/
public static int getSize(int measureSpec) {
return (measureSpec & ~MODE_MASK);
}
. . .
}
MeasureSpec提供了三种模式(SpecMode),分别为上面的UNSPECIFIED、EXACTLY、AT_MOST
<<是位运算符,一般用于二进制,代表向左移位,MODE_SHIFT是个常量,30,所以UNSPECIFIED就是0向左移位30位,EXACTLY是1向左移位30位,AT_MOST是2向左移位30位,如下表示:
UNSPECIFIED:
移位前:00000000 00000000 00000000 00000000
移位后:00000000 00000000 00000000 00000000
EXACTLY:
移位前:00000000 00000000 00000000 00000001
移位后:01000000 00000000 00000000 00000000
AT_MOST:
移位前:00000000 00000000 00000000 00000010
移位后:10000000 00000000 00000000 00000000
总的来说,其实就是MeasureSpec中,高两位代表SpecMode,低30位代表SpecSize。MeasureSpec类将SpecMode(模式)和SpecSize(大小)整合成一个int值,方法就是上面代码中的makeMesaureSpec方法,同时为了方便,也提供了方法可以从一个MeasureSpec值当中取出来原始的SpecMode和SpecSize,就是上面代码中的getMode和getSize,方法都很简单,这里可以简单解释下:
MODE_MASK是3向左移位30位,即11000000 00000000 0000000000000000,取反就是00111111 11111111 11111111 11111111。
把已整合的MeasureSpec值和MODE_MASK做&运算,即可得到SpecMode,将已整合的MeasureSpec值和取反后的MODE_MASK即可得到SpecSize。
另外,MeasureSpec和LayoutParams是有对应关系的,系统中是通过measureSpec来测量View的,但是在外部一般都是通过设置LayoutParams来改变View的,比如wrap_content和match_parent等。那么中间是怎么转换的呢,首先需要知道一点,就是View的MeasureSpec并不是唯一由LayoutParams来决定的,LayoutParams是需要和父容器一起才能决定view的MeasureSpec,在view测量的时候,系统会将LayoutParams在父容器的约束下转换成对应的MeasureSpec。
PS:顶级vi