zoukankan      html  css  js  c++  java
  • 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); }
  • 相关阅读:
    linux 下怎么看postgresql安装到哪个目录了?
    sqlserver 存储image 语句
    thinkphp5.1 配置使用
    百度车牌识别demo
    elastticsearch 安装
    InDB开发
    John爆破密码
    域传送漏洞
    新远程下载方式(IME)
    SSH端口转发
  • 原文地址:https://www.cnblogs.com/weixiao870428/p/3853532.html
Copyright © 2011-2022 走看看