介绍
安卓测量离不开一个类: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(),忽略