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 } else if (childDimension == LayoutParams.MATCH_PARENT) { // Child wants to be our size. So be it. // 子元素的 LayoutParams 是MATCH_PARENT resultSize = size; // 等于父容器尺寸 resultMode = MeasureSpec.EXACTLY; // Mode是EXACTLY } else if (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 } else if (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 } else if (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);}复制代码