注:根据网上资料整理如下
首先 onMeasure方法是为了得到各个View大小的函数
fill_parent-->public static final int EXACTLY = 1 << MODE_SHIFT;
wrap_content-->public static final int AT_MOST = 2 << MODE_SHIFT;
这是makeMeasureSpec方法的代码片段
public static int makeMeasureSpec(int size, int mode) { if (sUseBrokenMakeMeasureSpec) { return size + mode; } else { return (size & ~MODE_MASK) | (mode & MODE_MASK); } }
其中sUseBrokenMakeMeasureSpec的默认值是false:
/** * Use the old (broken) way of building MeasureSpecs. */ private static boolean sUseBrokenMakeMeasureSpec = false;
下面看一下sUseBrokenMakeMeasureSpec相关代码
1 public View(Context context) { 2 //此处省略无关代码......17 18 if (!sCompatibilityDone && context != null) { 19 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 20 21 // Older apps may need this compatibility hack for measurement. 22 sUseBrokenMakeMeasureSpec = targetSdkVersion <= JELLY_BEAN_MR1; 23 24 // Older apps expect onMeasure() to always be called on a layout pass, regardless 25 // of whether a layout was requested on that View. 26 sIgnoreMeasureCache = targetSdkVersion < KITKAT; 27 28 sCompatibilityDone = true; 29 } 30 }
在构造方法中对sUseBrokenMakeMeasureSpec的值进行了判断,代码走进第18行又出现了一个sCompatibilityDone,
追溯其值原来默认值是false,所以在view初始化的时候肯定会走进这一行的,当sdk版本小于JELLY_BEAN_MR1也就是4.2的时候会返回true,
好 现在回头看看也就是说4.2版本或一下makeMeasureSpec返回值是size + mode之后的版本都是(size & ~MODE_MASK) | (mode & MODE_MASK)。
现在说一下MeasureSpec中重要的方法
// 进位大小为2的30次方(int的大小为32位,所以进位30位就是要使用int的最高位和倒数第二位也就是32和31位做标志位) private static final int MODE_SHIFT = 30; // 运算遮罩,0x3为16进制,10进制为3,二进制为11。3向左进位30,就是11 00000000000(11后跟30个0) // (遮罩的作用是用1标注需要的值,0标注不要的值。因为1与任何数做与运算都得任何数,0与任何数做与运算都得0) private static final int MODE_MASK = 0x3 << MODE_SHIFT; // 0向左进位30,就是00 00000000000(00后跟30个0) public static final int UNSPECIFIED = 0 << MODE_SHIFT; // 1向左进位30,就是01 00000000000(01后跟30个0) public static final int EXACTLY = 1 << MODE_SHIFT; // 2向左进位30,就是10 00000000000(10后跟30个0) public static final int AT_MOST = 2 << MODE_SHIFT; /** * 根据提供的size和mode得到一个详细的测量结果 */ // measureSpec = size + mode; (注意:二进制的加法,不是10进制的加法!) // 这里设计的目的就是使用一个32位的二进制数,32和31位代表了mode的值,后30位代表size的值 // 例如size=100(4),mode=AT_MOST,则measureSpec=100+10000...00=10000..00100
//注意:最新版的sdk的makeMeasureSpec方法在文章首处,不过看过前文相信理解不难 public static int makeMeasureSpec(int size, int mode) { return size + mode; } /** * 通过详细测量结果获得mode */ // mode = measureSpec & MODE_MASK; // MODE_MASK = 11 00000000000(11后跟30个0),原理是用MODE_MASK后30位的0替换掉measureSpec后30位中的1,再保留32和31位的mode值。 // 例如10 00..00100 & 11 00..00(11后跟30个0) = 10 00..00(AT_MOST),这样就得到了mode的值 public static int getMode(int measureSpec) { return (measureSpec & MODE_MASK); } /** * 通过详细测量结果获得size */ // size = measureSpec & ~MODE_MASK; // 原理同上,不过这次是将MODE_MASK取反,也就是变成了00 111111(00后跟30个1),将32,31替换成0也就是去掉mode,保留后30位的size public static int getSize(int measureSpec) { return (measureSpec & ~MODE_MASK); }