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

首先把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的二进制表示方式

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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值