我们在读Android源码的时候都应该都接触过MeasureSpecMode这个类吧.很多人都能随口说出三种测量模式.那么我们今天看看这里面是怎么取值与使用值的.
再看下面的代码的时候我们了解一个基本的概念:
- &操作符,如果两个输入位都是1,则按位“与”操作符(&)生成一个输出位1,否则生成一个输出 位0.
- |操作符,如果两个输入位里只要有一个是1,则按位“或”操作符(|)生成一个输出位1,只有在两个输入位都是0的情况下,它才会生成一个输出位0。
- ~操作符,按位“非”(〜),也称为取反操作符,它属于一元操作符,只对一个操作数进行操作(其他按位操作符是二元操作符)。按位“非”生成与输入 //位相反的值——若输入0,则输出1,若输入1,则输出0。
- (<<) 左移位操作符能按照操作符右侧指定的位数将操作符左边的操作符向左移动(在低位补0).
- 有符号右位移操作符(>>) ,按照操作符右侧指定的位数将操作符左边的操作数向右移动.“有符号"右移位操作符使用"符号扩展”:若符号为正,则在高位插入0;若符号为负,则在高位插入1.
- 无符号右移位操作符(>>>),它使用零扩展:无论正负,都在高位插入1.
部分使用的例子可以参考这篇文章.
Andoird代码:View->MeasureSpec
public static class MeasureSpec {
private static final int MODE_SHIFT = 30;
//左移30位 11...000... 低位补0
private static final int MODE_MASK = 0x3 << MODE_SHIFT;
/** @hide */
@IntDef({UNSPECIFIED, EXACTLY, AT_MOST})
@Retention(RetentionPolicy.SOURCE)
public @interface MeasureSpecMode {}
//0左移动30位还是0 00...000...
public static final int UNSPECIFIED = 0 << MODE_SHIFT;
//1左移30位 低位补0 01...000...
public static final int EXACTLY = 1 << MODE_SHIFT;
//2左移30位 低位补0 10...000...
public static final int AT_MOST = 2 << MODE_SHIFT;
//给出int值的范围0到最大值
public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size,
@MeasureSpecMode int mode) {
if (sUseBrokenMakeMeasureSpec) {
//比如size height =200 那么 就是00....1100 1000 + 01...000... = 10...000..+11001000
return size + mode;
} else {
// (size & ~MODE_MASK) ~MODE_MASK取反(00...111...)与size得到后30位的值
// (mode & MODE_MASK) mode 是取前两位 高2位
// 或运算之后就将值合并了
return (size & ~MODE_MASK) | (mode & MODE_MASK);
}
}
public static int makeSafeMeasureSpec(int size, int mode) {
if (sUseZeroUnspecifiedMeasureSpec && mode == UNSPECIFIED) {
return 0;
}
return makeMeasureSpec(size, mode);
}
//获取mode模式
@MeasureSpecMode
public static int getMode(int measureSpec) {
// 与运算 获取高2位
return (measureSpec & MODE_MASK);
}
//获取size后30位
public static int getSize(int measureSpec) {
return (measureSpec & ~MODE_MASK);
}
static int adjust(int measureSpec, int delta) {
final int mode = getMode(measureSpec);
int size = getSize(measureSpec);
if (mode == UNSPECIFIED) {
// No need to adjust size for UNSPECIFIED mode.
return makeMeasureSpec(size, UNSPECIFIED);
}
size += delta;
if (size < 0) {
Log.e(VIEW_LOG_TAG, "MeasureSpec.adjust: new size would be negative! (" + size +
") spec: " + toString(measureSpec) + " delta: " + delta);
size = 0;
}
return makeMeasureSpec(size, mode);
}
}
总结一下:
- 上面使用到了位掩码(BitMask),简化了使用某些变量取值的操作,而且效率高.
- 或运算中就是把所需要的位进行合并.与运算配合位掩码来得到自己需要的位.
- 为了检查一个字节中的某些位,可以让这个字节和屏蔽字进行按位与操作,屏蔽字中与要检查的位对应的位全部为1,而其余的位(被屏蔽的位)全部为0. 就像我们的 MeasureSpecMode 字段里面定义的那样.我们要想获取高二位,而掩码MODE_MASK就是11000…这种.这是为了方便获取需要的位.我们 要想获取后30位,那就得将掩码MODE_MASK先取反,然后在进行与运算得到想要的后30位.
- size的取值范围也是0-最大值.再说一个View的height与width的大小怎么可能超过这个值呢.