public static class MeasureSpec {
private static final int MODE_SHIFT = 30;
private static final int MODE_MASK = 0x3 << MODE_SHIFT;
public static final int UNSPECIFIED = 0 << MODE_SHIFT;
public static final int EXACTLY = 1 << MODE_SHIFT;
public static final int AT_MOST = 2 << MODE_SHIFT;
public static int makeMeasureSpec(int size, int mode) {
if (sUseBrokenMakeMeasureSpec) {
return size + mode;
} else {
return (size & ~MODE_MASK) | (mode & MODE_MASK);
}
}
public static int getMode(int measureSpec) {
return (measureSpec & MODE_MASK);
}
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);
}
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();
}
}
public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
int specMode = MeasureSpec.getMode(spec);
int specSize = MeasureSpec.getSize(spec);
int size = Math.max(0, specSize - padding);
int resultSize = 0;
int resultMode = 0;
switch (specMode) {
// Parent has imposed an exact size on us
case MeasureSpec.EXACTLY:
if (childDimension >= 0) {
resultSize = childDimension;
resultMode = MeasureSpec.EXACTLY;
} else if (childDimension == LayoutParams.MATCH_PARENT) {
// Child wants to be our size. So be it.
resultSize = size;
resultMode = MeasureSpec.EXACTLY;
} else if (childDimension == LayoutParams.WRAP_CONTENT) {
// Child wants to determine its own size. It can't be
// bigger than us.
resultSize = size;
resultMode = MeasureSpec.AT_MOST;
}
break;
// Parent has imposed a maximum size on us
case MeasureSpec.AT_MOST:
if (childDimension >= 0) {
// Child wants a specific size... so be it
resultSize = childDimension;
resultMode = MeasureSpec.EXACTLY;
} else if (childDimension == LayoutParams.MATCH_PARENT) {
// Child wants to be our size, but our size is not fixed.
// Constrain child to not be bigger than us.
resultSize = size;
resultMode = MeasureSpec.AT_MOST;
} else if (childDimension == LayoutParams.WRAP_CONTENT) {
// Child wants to determine its own size. It can't be
// bigger than us.
resultSize = size;
resultMode = MeasureSpec.AT_MOST;
}
break;
// Parent asked to see how big we want to be
case MeasureSpec.UNSPECIFIED:
if (childDimension >= 0) {
// Child wants a specific size... let him have it
resultSize = childDimension;
resultMode = MeasureSpec.EXACTLY;
} else if (childDimension == LayoutParams.MATCH_PARENT) {
// Child wants to be our size... find out how big it should
// be
resultSize = 0;
resultMode = MeasureSpec.UNSPECIFIED;
} else if (childDimension == LayoutParams.WRAP_CONTENT) {
// Child wants to determine its own size.... find out how
// big it should be
resultSize = 0;
resultMode = MeasureSpec.UNSPECIFIED;
}
break;
}
return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
}
从中可以看出子View的MeasureSpec的计算过程被分为了3部分:
parentMeasureMode = EXACTLY
a. childDimension >=0 即子View设置的有具体的大小(如:100px),这种情况下childSpecSize即为其自身LayoutParams里指定的大小,childSpecMode为EXACTLY
b. childDimension = MATCH_PARENT 即子View的LayoutParams里设置的为MATCH_PARENT,这种情况下childSpecSize即为parentLeftSize(父容器剩余的空间),childSpecMode为EXACTLY
c. childDimension = WRAP_CONTENT 即子View的LayoutParams里设置的为WRAP_CONTENT,这种情况下childSpecSize为parentLeftSize(父容器剩余的空间),childSpecMode为AT_MOST
parentMeasureMode = AT_MOST
a. childDimension >=0 即子View设置的有具体的大小(如:100px),这种情况下childSpecSize即为其自身LayoutParams里指定的大小,childSpecMode为EXACTLY (同 1.a)
b. childDimension = MATCH_PARENT 即子View的LayoutParams里设置的为MATCH_PARENT,这种情况下childSpecSize即为parentLeftSize(父容器剩余的空间),childSpecMode为AT_MOST (同 1.c)
c. childDimension = WRAP_CONTENT 即子View的LayoutParams里设置的为WRAP_CONTENT,这种情况下childSpecSize即为parentLeftSize(父容器剩余的空间),childSpecMode为AT_MOST(同1.c)
parentMeasureMode = UNSPECIFIED
a. childDimension >=0 即子View设置的有具体的大小(如:100px),这种情况下childSpecSize即为其自身LayoutParams里指定的大小,childSpecMode为EXACTLY (同 1.a)
b. childDimension = MATCH_PARENT 即子View的LayoutParams里设置的为MATCH_PARENT,这种情况下childSpecSize为0,childSpecMode为UNSPECIFIED
c. childDimension = WRAP_CONTENT 即子View的LayoutParams里设置的为WRAP_CONTENT,这种情况下childSpecSize为0,childSpecMode为UNSPECIFIED(同3.b)