理解MeasureSpec

飛翔的超人發表於2019-03-29

1.左移和右移

java中的移位運算子有三種:

  • 左移<< 左移就是將左邊的運算元在記憶體中的二進位制資料左移指定的位數,左邊移空的部分補零。num << n, 相當於 num 乘以2的 n 次方

  • 右移>> 右移:右邊超出截掉,左邊補上符號位 (負的就填1 正的就填0)。num >> n, 相當於 num 除以2的 n 次方

  • 無符號右移>>> 無符號右移無論最高位是什麼,空位都補零

2.MeasureSpec構成

public static int makeMeasureSpec( int size, int mode) {
    if (sUseBrokenMakeMeasureSpec) {
                return size + mode;
            } else {
                return (size & ~MODE_MASK) | (mode & MODE_MASK);
            }
     }  
}    

複製程式碼

MeasureSpec其實就是一個32位的int型別值(4個位元組32bit),由高2位的mode和低30位的size組成

3.getMode

MeasureSpec有三種mode。UNSPECIFIED , EXACTLY , AT_MOST

        private static final int MODE_SHIFT = 30;
        private static final int MODE_MASK  = 0x3 << MODE_SHIFT;

        /**
         * Measure specification mode: The parent has not imposed any constraint
         * on the child. It can be whatever size it wants.
         */
        public static final int UNSPECIFIED = 0 << MODE_SHIFT;

        /**
         * Measure specification mode: The parent has determined an exact size
         * for the child. The child is going to be given those bounds regardless
         * of how big it wants to be.
         */
        public static final int EXACTLY     = 1 << MODE_SHIFT;

        /**
         * Measure specification mode: The child can be as large as it wants up
         * to the specified size.
         */
        public static final int AT_MOST     = 2 << MODE_SHIFT;

複製程式碼
  • UNSPECIFIED = 0 << MODE_SHIFT; 即: 00000000 00000000 00000000 00000000
  • EXACTLY = 1 << MODE_SHIFT; 即: 01000000 00000000 00000000 00000000
  • AT_MOST = 2 << MODE_SHIFT; 即: 10000000 00000000 00000000 00000000
public static int getMode(int measureSpec) {
            //noinspection ResourceType
            return (measureSpec & MODE_MASK);
}
複製程式碼

getMode()方法中,MODE_MASK=11000000 00000000 00000000 00000000,將32位的measureSpec和11000000 00000000 00000000 00000000進行&運算,最終得到的肯定是measureSpec的高2位。

比如生成measureSpec時傳入AT_MOST。那麼measureSpec為10000000 00000000 00000000 00000101,

measureSpec & MODE_MASK 即
10000000 00000000 00000000 00000101  
&
11000000 00000000 00000000 00000000
=
10000000 00000000 00000000 00000000
=AT_MOST
複製程式碼

傳入measureSpec後,measureSpec的低30位肯定全部為0,最終只剩下高2位。而measureSpec的高2位正好就是mode

4.getSize

public static int getSize(int measureSpec) {
            return (measureSpec & ~MODE_MASK);
}
複製程式碼

getSize方法原理跟getMode一樣,只是先將MODE_MASK取反, ~MODE_MASK=00111111 11111111 11111111 11111111 然後measureSpec和~MODE_MASK進行&運算,結果肯定為measureSpec的低30位了,因為高2位和00進行&運算肯定是00了

5.總結

自定義View時會經常使用到MeasureSpec,通過它拿size或者mode,其實只是生成一個32位的int值,取其高2位或者低30位。提高了執行效率