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