安卓开发学习之MeasureSpec

介绍

安卓测量离不开一个类:MeasureSpec,它是view的尺寸和模式的封装,也是View的一个内部类


属性

public static class MeasureSpec {
        private static final int MODE_SHIFT = 30; // 
        private static final int MODE_MASK  = 0x3 << MODE_SHIFT;

        /** @hide */
        @IntDef({UNSPECIFIED, EXACTLY, AT_MOST})
        @Retention(RetentionPolicy.SOURCE)
        public @interface MeasureSpecMode {}

        // 父view对子view没有限制,子view要多大就多大
        public static final int UNSPECIFIED = 0 << MODE_SHIFT;

        // 精确模式,子view尺寸严格按着父view的要求来
        public static final int EXACTLY     = 1 << MODE_SHIFT;

        // 父view规定子view的最大尺寸
        public static final int AT_MOST     = 2 << MODE_SHIFT;

        ....

}


方法

1、makeMeasureSpec()

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);
            }
}

这个方法用来把size和mode包装起来,size是子view的尺寸,mode是父view对子view的尺寸限制


2、makeSafeMeasureSpec()

public static int makeSafeMeasureSpec(int size, int mode) {
            if (sUseZeroUnspecifiedMeasureSpec && mode == UNSPECIFIED) {
                return 0;
            }
            return makeMeasureSpec(size, mode);
}

这个方法是为了兼容sdk<=23的版本和一些系统view,也是一些问题的原因,比如ScrollView嵌套下的ListView只显示第一行,就是因为这儿,ScrollView给子view的heightSpec直接返回了0,导致mode也是0,故而在ListView的高度只是第一项的高度。解决方法就是自定义一个view,继承ListView,覆写onMeasure(),只不过要把heightSpec的mode设置成AT_MOST,这样就可以显示所有的项了。


3、getMode()和getSize()

       @MeasureSpecMode
        public static int getMode(int measureSpec) {
            //noinspection ResourceType
            return (measureSpec & MODE_MASK);
        }

        public static int getSize(int measureSpec) {
            return (measureSpec & ~MODE_MASK);
        }

就是从measureSpec里获取mode和size


4、adjust()

        static int adjust(int measureSpec, int delta) {
            final int mode = getMode(measureSpec);
            int size = getSize(measureSpec);
            if (mode == UNSPECIFIED) {
                // No need to adjust size for UNSPECIFIED mode.
                return makeMeasureSpec(size, UNSPECIFIED);
            }
            size += delta;
            if (size < 0) {
                Log.e(VIEW_LOG_TAG, "MeasureSpec.adjust: new size would be negative! (" + size +
                        ") spec: " + toString(measureSpec) + " delta: " + delta);
                size = 0;
            }
            return makeMeasureSpec(size, mode);
        }

根据delta调整measureSpec的size,这个方法只在View.onMeasure()方法中被调用过,平时基本也用不到


5、toString(),忽略


猜你喜欢

转载自blog.csdn.net/qq_37475168/article/details/80280668