要搞清楚 onMeasure(), 我们先来看一下方法原型吧
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {....}
刚刚读源码的童鞋可能并不知道 widthMeasureSpec,heightMeasureSpec 这两个参数的作用是什么这两个参数实际上可以通过
- MeasureSpec.getSize()
- ,
- MeasureSpec.getMode()
这两个方法来判断该 view 被测量后的尺寸那么, 为什么还要通过
MeasureSpec.getMode()
呢? 这就是接下来要说明的重点 ### 以下是 MeasureSpec 中剔除部分代码之后的 getMode() 实现方式
- private static final int MODE_SHIFT = 30;
- private static final int MODE_MASK = 0x3 << MODE_SHIFT;
- // 我们通过位运算可以知道, MODE_MASK 实际上等于 11 左移 30 位的二进制, 在 Java 中 int 占 32 位, 所以这里就表示的是 int 中最高位为 11, 其余 30 位为 0 的二进制数
- public static final int UNSPECIFIED = 0 << MODE_SHIFT;
- public static final int EXACTLY = 1 << MODE_SHIFT;
- public static final int AT_MOST = 2 << MODE_SHIFT;
- ....
- public static int getMode(int measureSpec) {
- //measureSpec 就是我们传进来的 widthMeasureSpec 或者 heightMeasureSpec
- // 它与上 measureSpec, 低 30 位就全部都清零了
- // 将返回值与 UNSPECIFIEDEXACTLYAT_MOST 比较就能得到 measureSpec 的 mode 了
- return (measureSpec & MODE_MASK);
- }
通过以上的注释 style 分析, 我们知道了 MeasureSpec 是如何计算 mode 了, 那么为什么要计算这些 mode 呢? 与 size 又有什么关系呢? View 的 MeasureSpec Mode 有三种, 分别为: UNSPECIFIED,EXACTLY,AT_MOST, 他们的规则如下 (要注意一点的是, 在子 view 中计算的 mode, 是 parent view 告诉它的):
UNSPECIFIED:parent view 对子 view 没有任何的约束, 子 view 可以任一尺寸, 但必须要有发生场景: 对于一个 ScorllView 来说, 它的高度通常与子 view 的高度无关, 也就是说, 子 view 的高度加起来有多高, 那么 ScrollView 就有多高在这种情况下, 子 view 的 mode 就会为 UNSPECIFIED
EXACTLY:parent view 已经有了确切的 size, 子 view 的大小不能够超过 parent 的大小发生场景: 在 parent view 指定大小或者为 match_parent 的时候, 子 view 会得到这个 mode
AT_MOST: 在这种模式下, 子 view 能够尽可能大的达到设定的尺寸或者原尺寸发生场景: 在 parent view 指定大小或者 match_parent 的情况下, 子 view 为 wrap_content, 那么 mode 将会为 AT_MOST
通过以上对 mode 的规则分析, 我们就能够知道, 在 onMeasure 中要搞到尺寸, 是需要根据 mode 来搞的
于是我们可以根据规则写出如下代码:
- public static int getDefaultSize(int size, int measureSpec) {
- int result = size;
- int specMode = MeasureSpec.getMode(measureSpec);
- int specSize = MeasureSpec.getSize(measureSpec);
- switch (specMode) {
- case MeasureSpec.UNSPECIFIED:
- result = size;// 如果不指定 size, 那么我们就使用默认的 size
- break;
- case MeasureSpec.AT_MOST:
- case MeasureSpec.EXACTLY:
- result = specSize;// 这两种 mode 都允许我们直接使用测量出来的 size
- break;
- }
- return result;
- }
来源: https://juejin.im/post/5a9241fef265da4e721c96f2