/* * @param spec 父 view 的 MeasureSpec * @param padding 父 view 设置的 padding * @param childDimension 该 view 希望设置的大小(即 LayoutParam 的 width/height or xml 中设置的 layout_width/layout_height) * @return 返回该 view 的 MeasureSpec */ publicstaticintgetChildMeasureSpec(int spec, int padding, int childDimension){ //获取父 view 的 mode int specMode = MeasureSpec.getMode(spec); //获取父 view 的 size 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 //父 view 的大小是固定的 case MeasureSpec.EXACTLY: if (childDimension >= 0) { //如果子 view 设置了大小,则使用子 view 自己设置的大小和,mode 为 EXACTLY resultSize = childDimension; resultMode = MeasureSpec.EXACTLY; } elseif (childDimension == LayoutParams.MATCH_PARENT) { //子 view 设置为 MATCH_PARENT,则使用父 view 的大小,mode 为 EXACTLY resultSize = size; resultMode = MeasureSpec.EXACTLY; } elseif (childDimension == LayoutParams.WRAP_CONTENT) { //子 view 要决定自己的大小(设置为 WRAP_CONTENT),不能超过父 view,则使用父 view 的大小,mode 为 AT_MOST(最大不能超过 size) // 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 //父 view 没有固定大小,但有上限 case MeasureSpec.AT_MOST: if (childDimension >= 0) { // Child wants a specific size... so be it //如果子 view 设置了大小,则使用子 view 自己设置的大小,mode 为 EXACTLY resultSize = childDimension; resultMode = MeasureSpec.EXACTLY; } elseif (childDimension == LayoutParams.MATCH_PARENT) { //子view 要求跟父 view 一样大,但父 view 是不固定的 //只能约束子 view 不超过父 view,则使用父 view 的大小,mode 为 AT_MOST(最大不能超过 size) // 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; } elseif (childDimension == LayoutParams.WRAP_CONTENT) { //子 view 要决定自己的大小(设置为 WRAP_CONTENT),不能超过父 view,则使用父 view 的大小,mode 为 AT_MOST(最大不能超过 size) // 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 //父 view 没有限制,可以为任何大小 case MeasureSpec.UNSPECIFIED: if (childDimension >= 0) { //如果子 view 设置了大小,则使用子 view 自己设置的大小,mode 为 EXACTLY // Child wants a specific size... let him have it resultSize = childDimension; resultMode = MeasureSpec.EXACTLY; } elseif (childDimension == LayoutParams.MATCH_PARENT) { //子view 要求跟父 view 一样大,则继续看看子 view应该多大 //在 Api 23 以下设置 size 为 0,Api 23以上为父 view 的 size //mode 设置为 UNSPECIFIED resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size; resultMode = MeasureSpec.UNSPECIFIED; } elseif (childDimension == LayoutParams.WRAP_CONTENT) { //子 view 要决定自己的大小(设置为 WRAP_CONTENT), //在 Api 23 以下设置 size 为 0,Api 23以上为父 view 的 size //mode 设置为 UNSPECIFIED resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size; resultMode = MeasureSpec.UNSPECIFIED; } break; } //noinspection ResourceType //最后将 size 和 mode 组装并返回 return MeasureSpec.makeMeasureSpec(resultSize, resultMode); }