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);
}
複製代碼
private static int getRootMeasureSpec(int windowSize, int rootDimension) {
int measureSpec;
switch (rootDimension) {
case ViewGroup.LayoutParams.MATCH_PARENT:
// Window can't resize. Force root view to be windowSize. measureSpec = MeasureSpec.makeMeasureSpec(windowSize,MeasureSpec.EXACTLY); break; case ViewGroup.LayoutParams.WRAP_CONTENT: // Window can resize. Set max size for root view. measureSpec = MeasureSpec.makeMeasureSpec(windowSize,MeasureSpec.AT_MOST); break; default: // Window wants to be an exact size. Force root view to be that size. measureSpec = MeasureSpec.makeMeasureSpec(rootDimension,MeasureSpec.EXACTLY); break; } return measureSpec; } 複製代碼
public static int getDefaultSize(int size, int measureSpec)
int result = size;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
switch (specMode) {
case MeasureSpec.UNSPECIFIED:
result = size;
break;
case MeasureSpec.AT_MOST:
case MeasureSpec.EXACTLY:
result = specSize;
break;
}
return result;
}
複製代碼
protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {
final int size = mChildrenCount;
final View[] children = mChildren;
for (int i = 0; i < size; ++i) {
final View child = children[i];
if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {
measureChild(child, widthMeasureSpec, heightMeasureSpec);
}
}
}
protected void measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec) {
final LayoutParams lp = child.getLayoutParams();
final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, mPaddingLeft + mPaddingRight, lp.width);
final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, mPaddingTop + mPaddingBottom, lp.height);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
複製代碼
/**
* spec: 父容器的 MeasureSpec
* padding: 父容器的Padding + 子View的Margin + 已經用掉的大小(widthUsed)
* childDimension: 表示該子元素的 LayoutParams 屬性的值(lp.width、lp.height)
*/
public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
int specMode = MeasureSpec.getMode(spec);
// specSize 是父容器的尺寸
int specSize = MeasureSpec.getSize(spec);
// size 是子元素可用的尺寸, 即父容器減去padding剩下的尺寸大小
int size = Math.max(0, specSize - padding);
// resultSize 和 resultMode 是最終要返回的結果
int resultSize = 0;
int resultMode = 0;
// 根據父容器的 specMode 測量模式進行分別處理
switch (specMode) {
// Parent has imposed an exact size on us
// 父容器的測量模式是EXACTLY
case MeasureSpec.EXACTLY:
// 根據子元素的 LayoutParams 屬性分別處理
if (childDimension >= 0) {
// 子元素的 LayoutParams 是精確值(dp/px)
resultSize = childDimension; // 等於設置的尺寸
resultMode = MeasureSpec.EXACTLY; // Mode是EXACTLY
} elseif (childDimension == LayoutParams.MATCH_PARENT) {
// Child wants to be our size. So be it.
// 子元素的 LayoutParams 是MATCH_PARENT
resultSize = size; // 等於父容器尺寸
resultMode = MeasureSpec.EXACTLY; // Mode是EXACTLY
} elseif (childDimension == LayoutParams.WRAP_CONTENT) {
// Child wants to determine its own size. It can't be // bigger than us. // 子元素的 LayoutParams 是WRAP_CONTENT resultSize = size; // 暫時等於父容器尺寸 resultMode = MeasureSpec.AT_MOST; // Mode是AT_MOST } break; // Parent has imposed a maximum size on us // 父容器的測量模式是AT_MOST case MeasureSpec.AT_MOST: if (childDimension >= 0) { // Child wants a specific size... so be it // 子元素的 LayoutParams 是精確值(dp/px) resultSize = childDimension; // 等於設置的尺寸 resultMode = MeasureSpec.EXACTLY; // Mode是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; // Mode是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; // Mode是AT_MOST
}
break;
// Parent asked to see how big we want to be
// 父容器的測量模式是UNSPECIFIED
case MeasureSpec.UNSPECIFIED:
if (childDimension >= 0) {
// Child wants a specific size... let him have it
resultSize = childDimension; // 等於設置的尺寸
resultMode = MeasureSpec.EXACTLY; // Mode是EXACTLY
} elseif (childDimension == LayoutParams.MATCH_PARENT) {
// Child wants to be our size... find out how big it should
// be
resultSize = ? 0; // 暫等於0, 值未定
resultMode = MeasureSpec.UNSPECIFIED; // Mode是UNSPECIFIED
} elseif (childDimension == LayoutParams.WRAP_CONTENT) {
// Child wants to determine its own size.... find out how
// big it should be
resultSize = 0; // 暫等於0, 值未定
resultMode = MeasureSpec.UNSPECIFIED; // Mode是UNSPECIFIED
}
break;
}
//noinspection ResourceType
return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
}
複製代碼
for (int i = 0; i < count; ++i) {
final View child = getVirtualChildAt(i);
...
// Determine how big this child would like to be. If this or
// previous children have given a weight, then we allow it to
// use all available space (and we will shrink things later
// if needed).
// 遍歷子元素並測量它們
measureChildBeforeLayout(child, i, widthMeasureSpec, 0,
heightMeasureSpec, usedHeight);
// mTotalLength 是用來存儲 LinearLayout 在豎直方向上的高度
final int childHeight = child.getMeasuredHeight();
final int totalLength = mTotalLength;
// 每測量一個子元素,mTotalLength 會保存它的高度以及它豎直方向上的 margin
mTotalLength = Math.max(totalLength, totalLength + childHeight +
lp.topMargin +lp.bottomMargin + getNextLocationOffset(child));
複製代碼
/**
* size: 是 mTotalLength, 即豎直方向上全部子元素的高度總和
* measureSpec: 父容器傳過來的指望尺寸, 即剩餘空間
*/
public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) {
final int specMode = MeasureSpec.getMode(measureSpec);
final int specSize = MeasureSpec.getSize(measureSpec);
final int result;
switch (specMode) {
case MeasureSpec.AT_MOST:
if (specSize < size) {
result = specSize | MEASURED_STATE_TOO_SMALL;
} else {
result = size;
}
break;
case MeasureSpec.EXACTLY:
result = specSize;
break;
case MeasureSpec.UNSPECIFIED:
default:
result = size;
}
return result | (childMeasuredState & MEASURED_STATE_MASK);
}
複製代碼