Android MeasureSpec完全解析——手把手教你分析

来源:互联网 发布:win10 1709 知乎 编辑:程序博客网 时间:2024/06/06 16:36

首先把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;        public static final int EXACTLY     = 1 << MODE_SHIFT;        public static final int AT_MOST     = 2 << MODE_SHIFT;

上面的是定义了一些常亮,最后3个我们非常熟悉,就是我们常用的3种测量模式。前两个是做变换用的两个常亮,后面分析会提到这两个常亮的作用。

我们常用的两个方法:

        // 将size和mode合成一个32位的int值        public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, @MeasureSpecMode int mode) {            if (sUseBrokenMakeMeasureSpec) {                return size + mode;            } else {                return (size & ~MODE_MASK) | (mode & MODE_MASK);            }        }        // 拆解出来mode        public static int getMode(int measureSpec) {            return (measureSpec & MODE_MASK);        }        // 拆解出来size        public static int getSize(int measureSpec) {            return (measureSpec & ~MODE_MASK);        }

先看makeMeasureSpec方法,这是将一个size和一个mode组合成一个int值,方法的实现中有一个判断sUseBrokenMakeMeasureSpec值得操作,这个值是什么呢,源码是这样写的:

    /**     * Use the old (broken) way of building MeasureSpecs.     */    private static boolean sUseBrokenMakeMeasureSpec = false;    // 在View的构造函数中sUseBrokenMakeMeasureSpec是这样初始化的    sUseBrokenMakeMeasureSpec = targetSdkVersion <= JELLY_BEAN_MR1;

假设我们的size的值是10,用二进制表示则是:
0000 0000 0000 0000 0000 0000 0000 1010
我们用的mode是EXACTLY,二进制表示是:
0100 0000 0000 0000 0000 0000 0000 0000

1 我们先分析sUseBrokenMakeMeasureSpec == false的情况,也就是当前系统版本大于JELLY_BEAN_MR1

这时返回值是return (size & ~MODE_MASK) | (mode & MODE_MASK)这个东西具体怎么计算的呢?
在java中,int在内存中占用32位的长度,结合前面的定义:
MODE_SHIFT = 30
MODE_MASK = 0x3 << MODE_SHIFT;

0X3用二进制数表示是
0000 0000 0000 0000 0000 0000 0000 0011,左移30位之后变成了
1100 0000 0000 0000 0000 0000 0000 0000 这是MODE_MASK的值

那么~MODE_MASK的值是按位取反后变成了:
0011 1111 1111 1111 1111 1111 1111 1111

size & ~MODE_MASK按位与的值是:
0000 0000 0000 0000 0000 0000 0000 1010

同理我们可以计算出(mode & MODE_MASK)的值是:
0100 0000 0000 0000 0000 0000 0000 0000

(size & ~MODE_MASK) | (mode & MODE_MASK)的值是:
0100 0000 0000 0000 0000 0000 0000 1010

2 我们在分析sUseBrokenMakeMeasureSpec == true的情况:

这时方法返回的是size + mode,mode转化为10进制的值是1073741824,加上我们的size(10)是1073741834,转为二进制是:
0100 0000 0000 0000 0000 0000 0000 1010
可以看出和我们上面分析的结果是一样的,上面的方式其实就是在求和。至于为什么会分成两种情况,目前我也不清楚,有高手知道可以留言。

下面分析getMode方法,返回值是measureSpec & MODE_MASK,我们上面计算的结果是:
0100 0000 0000 0000 0000 0000 0000 1010
MODE_MASK
1100 0000 0000 0000 0000 0000 0000 0000
按位与后是
0100 0000 0000 0000 0000 0000 0000 0000,就是我们的mode。

同理可以分析getSize方法,返回值是measureSpec & ~MODE_MASK,是
0100 0000 0000 0000 0000 0000 0000 1010
0011 1111 1111 1111 1111 1111 1111 1111 按位与
得到的就是
0000 0000 0000 0000 0000 0000 0000 1010,就是10的二进制表示方式

以上就是全部内容,总体没有什么大的难度,就是位运算,位运算明白了就透彻了。

0 0
原创粉丝点击