Android Measure中对应方法解析

注:根据网上资料整理如下

 

首先 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); }
posted @ 2014-07-18 14:56  微笑yy520  阅读(333)  评论(0编辑  收藏  举报