在自定义一个View的时候,常常会使用MeasureSpec,MeasureSpec是什么呢,可以翻译为测量规范,测量标准,测量说明。
MeasureSpec是一个测量说明,表示父View传递给子View的布局要求和说明,封装了size和mode,而且包含了高度和宽度的size和mode。
MeasureSpec的mode有三种:
/**
* A MeasureSpec encapsulates the layout requirements passed from parent to child.
* Each MeasureSpec represents a requirement for either the width or the height.
* A MeasureSpec is comprised of a size and a mode. There are three possible
* modes:
*
* 一个MeasureSpec类封装了从父View传递给子View的布局要求
* 每个MeasureSpec类代表了一个宽度和高度的要求
* 一个MeasureSpec类由size和mode组成,有三种可能的模式
*
* <dl>
* <dt>UNSPECIFIED</dt>
* <dd>
* The parent has not imposed any constraint on the child. It can be whatever size
* it wants.
* </dd>
*
* <dt>EXACTLY</dt>
* <dd>
* 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.
* </dd>
*
* <dt>AT_MOST</dt>
* <dd>
* The child can be as large as it wants up to the specified size.
* </dd>
* </dl>
* <pre>
*
* UNSPECIFIED(未指定):
* 父View没有对子View施加任何的约束,子View可以是任意大小
* EXACTLY(精确):
* 父View已经为子View确定了具体的大小,
* 子View已经被给予了大小,忽略子View想要多大的尺寸
* AT_MOST(最大):
* 子View可以和指定的大小一样大
* <pre/>
* MeasureSpecs are implemented as ints to reduce object allocation. This class
* is provided to pack and unpack the <size, mode> tuple into the int.
*
* 为减少对象分配,MeasureSpecs被实现为二进制整数
* 此类提供了压缩和解压缩<size,mode>组到整数里
* (也就是说可以把<size,mode>封装到MeasureSpecs中,也可以从MeasureSpecs中获取<size,mode>)
*/
public static class MeasureSpec {
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.
*
* 测量规范模式:父View没有给子View强加任何约束,子View可以是任何想要的尺寸。
*/
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.
* 测量规范模式:父View已经给子View确定了具体的大小。 子View已经被给予了大小,忽略子View想要多大的尺寸
*/
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.
*
* 测量规范模式: 子View可以和指定的大小一样大
*/
public static final int AT_MOST = 2 << MODE_SHIFT;
/**
* Creates a measure specification based on the supplied size and mode.
* 基于提供的size和mode创建一个测量规范
*
* The mode must always be one of the following:
* mode必须为以下三者之一
* <ul>
* <li>{@link android.view.View.MeasureSpec#UNSPECIFIED}</li>
* <li>{@link android.view.View.MeasureSpec#EXACTLY}</li>
* <li>{@link android.view.View.MeasureSpec#AT_MOST}</li>
* </ul>
*
* <p><strong>Note:</strong> On API level 17 and lower, makeMeasureSpec's
* implementation was such that the order of arguments did not matter
* and overflow in either value could impact the resulting MeasureSpec.
* {@link android.widget.RelativeLayout} was affected by this bug.
* Apps targeting API levels greater than 17 will get the fixed, more strict
* behavior.</p>
* 笔记:在API 17和以下,makeMeasureSpec的实现,参数顺序没有问题,溢出值可能会影响MeasureSpec结果。
*
* @param size the size of the measure specification
* @param mode the mode of the measure specification
* @return the measure specification based on size and mode
*/
public static int makeMeasureSpec(int size, int mode) {
if (sUseBrokenMakeMeasureSpec) {
return size + mode;
} else {
return (size & ~MODE_MASK) | (mode & MODE_MASK);
}
}
/**
* Extracts the mode from the supplied measure specification.
* 从提供的测量规范提取mode
* @param measureSpec the measure specification to extract the mode from
* 从测量规范提取mode
*
* @return {@link android.view.View.MeasureSpec#UNSPECIFIED},
* {@link android.view.View.MeasureSpec#AT_MOST} or
* {@link android.view.View.MeasureSpec#EXACTLY}
*/
public static int getMode(int measureSpec) {
return (measureSpec & MODE_MASK);
}
/**
* Extracts the size from the supplied measure specification.
* 从提供的测量规范提取size
* @param measureSpec the measure specification to extract the size from
* 从测量规范提取size
* @return the size in pixels defined in the supplied measure specification
* 单位:px,返回在提供的测量规范中的size
*/
public static int getSize(int measureSpec) {
return (measureSpec & ~MODE_MASK);
}
static int adjust(int measureSpec, int delta) {
final int mode = getMode(measureSpec);
if (mode == UNSPECIFIED) {
// No need to adjust size for UNSPECIFIED mode.
return makeMeasureSpec(0, UNSPECIFIED);
}
int size = getSize(measureSpec) + 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);
}
/**
* Returns a String representation of the specified measure
* specification.
*
* 返回一个指定的测量规范的字符串表示。
* @param measureSpec the measure specification to convert to a String
* 转换成String的测量规范
* @return a String with the following format: "MeasureSpec: MODE SIZE"
* 返回一个String,带有如下格式:"MeasureSpec: MODE SIZE"
*/
public static String toString(int measureSpec) {
int mode = getMode(measureSpec);
int size = getSize(measureSpec);
StringBuilder sb = new StringBuilder("MeasureSpec: ");
if (mode == UNSPECIFIED)
sb.append("UNSPECIFIED ");
else if (mode == EXACTLY)
sb.append("EXACTLY ");
else if (mode == AT_MOST)
sb.append("AT_MOST ");
else
sb.append(mode).append(" ");
sb.append(size);
return sb.toString();
}
}
1、 MeasureSpec.UNSPECIFIED,表示父View对子View大小没有指定,子view可以是任意的大小
当子View的宽高设置为0或者没有设置时,mode为未指定。
2、 MeasureSpec.AT_MOST,表示子View的尺寸最大能达到多少。
当控件的layout_width或layout_height指定为WRAP_CONTENT时,子view大小一般随着他的子view或内容进行变化,此时控件尺寸只要不超过父view允许的最大尺寸即可。
3、 MeasureSpec.EXACTLY,表示父控件给定了精确的尺寸。
当控件的layout_width或layout_height指定为具体数值或者为FILL_PARENT时,都表示控件大小是精确尺寸。
size和mode都是用二进制整数表示:
模式进位:
private static final int MODE_SHIFT = 30;在源码中,MODE_SHIFT表示mode进位转换,int型有32位,进位30位,表示用int型的31位和32位作为标识位。
31位二进制数为:
/**
|--------|--------|--------|--------|
01000000 00000000 00000000 00000000
|--------|--------|--------|--------|
*/
32位二进制数为:
/**
|--------|--------|--------|--------|
10000000 00000000 00000000 00000000
|--------|--------|--------|--------|
*/
MODE_MASK:mode遮罩,就是说把其他不要的盖住,其实是二进制的与运算。0x3为十六进制,十进制为3
private static final int MODE_MASK = 0x3 << MODE_SHIFT; MODE_SHIFT 进位30位表示二进制数就是:
/**
|--------|--------|--------|--------|
11000000 00000000 00000000 00000000
|--------|--------|--------|--------|
*/
public static final int UNSPECIFIED = 0 << MODE_SHIFT; 0左移30位表示二进制数为:
/**
|--------|--------|--------|--------|
00000000 00000000 00000000 00000000
|--------|--------|--------|--------|
*/
public static final int EXACTLY = 1 << MODE_SHIFT;1左移30位表示二进制数为: /**
|--------|--------|--------|--------|
01000000 00000000 00000000 00000000
|--------|--------|--------|--------|
*/
public static final int AT_MOST = 2 << MODE_SHIFT;2左移30位表示二进制数为:
/**
|--------|--------|--------|--------|
10000000 00000000 00000000 00000000
|--------|--------|--------|--------|
*/
生成测量说明:测量说明是尺寸和模式的二进制数相加得到的 public static int makeMeasureSpec(int size, int mode) {
if (sUseBrokenMakeMeasureSpec) {
return size + mode;
} else {
return (size & ~MODE_MASK) | (mode & MODE_MASK);
}
}
获取模式,返回值为测量说明和MODE_MASK相与得到的
public static int getMode(int measureSpec) {
return (measureSpec & MODE_MASK);
}
获取尺寸,返回值为测量说明和MODE_MASK取反值再相与得到的
public static int getSize(int measureSpec) {
return (measureSpec & ~MODE_MASK);
}