MeasureSpec是自定义View是重写View的onMeasure的一个参数,利用这个参数我们可以准确测量View的宽高。
MeasureSpec有一个很有意思的思想,其实MeasureSpec类中有两个属性,但是Android并不像我们平常一样
private int mode;
private int size;
而是采取一种合并的方式,将mode和size合并为一个32位的int值。高2位代表mode,低30位代表size,还提供了getSize和getMode两个方法获取。因为看源码晕晕的,所以特意复习了一下java的位移,这里记录一下。
// i为0000 0011 -> 3
int i = 3;
// i左移1位,b为0000 0110 -> 6
int b = i << 1;
// i右移1位,c为0000 0001 -> 1
int c = i >> 1;
// b | c,d为0000 0111 -> 7
int d = b | c;
// b & c,e为0000 0000 -> 0
int e = b & c;
// ~i,f为1111 1100
int f = ~i;
上面的代码足够让我理解位移的知识点了。更深入的可以自行查找!!回到MeasureSpec,getMode有3中方式:
(1)UNSPECIFIED
不对View做任何的限制,只要用在系统的View,so i don`t care !!
(2)EXACTLY(精确模式)
View已经指定了精确的值,也是最终View的大小。对应LayoutParams中match_parent或具体的width。
(3)AT_MOST(最大模式)
View没有指定精确大小,取决于View的内容,刚好装够内容就行,但是不能超过父容器剩余大小。对应LayoutParams的wrap_content。
各种模式错综复杂,子View的大小还会受限制于父容器的大小,关系如表
作者也简单总结了一下:
当子View指定dp/px时,无论父容器是哪种模式,子View都是EXACTLY模式,而且大小都是子View指定的大小。
当子View指定match_parent时,受父容器影响。如果父容器也是EXACTLY模式,那么子View也是EXACTLY模式,而且大小是父容器剩余大小。如果父容器是AT_MOST模式,那么子View也是AT_MOST模式,大小最大也是父容器剩余大小。
当子View指定wrap_content时,无论父容器是哪种模式,子View都是AT_MOST模式,最大大小是父容器剩余大小。
所以View的测量大小,需要结合自身的LayoutParams和父容器的模式,也就是MeasureSpec。