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;
// 生成MeasureSpec的32位int值 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); }
childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth,lp.width); childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight,lp.height); performMeasure(childWidthMeasureSpec,childHeightMeasureSpec); 接着再看一下getRootMeasureSpec方法的实现: 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. // 精确大小。大小就是LayoutParams中指定的大小 measureSpec = MeasureSpec.makeMeasureSpec(rootDimension,Measure-Spec.EXACTLY); break; } return measureSpec; }
/** * Utility to return a default size. Uses the supplied size if the * MeasureSpec imposed no constraints. Will get larger if allowed * by the MeasureSpec. * * @param size Default size for this view 当前View的默认尺寸 * @param measureSpec Constraints imposed by the parent 父View施加的measureSpec约束 * @return The size this view should be. * 获取View测量出来的默认尺寸的大小。传入的参数是尺寸和MeasureSpec * 我们要清晰理解这个传入尺寸和MeasureSpec */ public static int getDefaultSize(int size, int measureSpec) { // 设置默认大小 int result = size; // 获取父View施加的宽/高测量规格的模式 & 测量大小 int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec);
switch (specMode) { case MeasureSpec.UNSPECIFIED: // 模式为UNSPECIFIED时,使用提供的默认大小 = 参数Size result = size; break; // 模式为AT_MOST,EXACTLY时,使用View测量后的宽/高值 = measureSpec中的Size case MeasureSpec.AT_MOST: case MeasureSpec.EXACTLY: result = specSize; break; } // 返回View的宽/高值 return result; }
/** * Ask one of the children of this view to measure itself, taking into * account both the MeasureSpec requirements for this view and its padding. * The heavy lifting is done in getChildMeasureSpec. * * @param child The child to measure * @param parentWidthMeasureSpec The width requirements for this view * @param parentHeightMeasureSpec The height requirements for this view */ protectedvoidmeasureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec) { // 获取Child的LayoutParams.主要是为了获取View的宽高等尺寸 finalLayoutParamslp= child.getLayoutParams(); /// 这个方法很重要,我们可看一下,这个参数传入的parentWidthMeasureSpec(父View的测量规格)、父View的padding、子View的宽度 finalintchildWidthMeasureSpec= getChildMeasureSpec(parentWidthMeasureSpec, mPaddingLeft + mPaddingRight, lp.width); /// 这个方法很重要,我们可看一下,这个参数传入的parentHeightMeasureSpec(父View的测量规格)、父View的padding、子View的高度 finalintchildHeightMeasureSpec= getChildMeasureSpec(parentHeightMeasureSpec, mPaddingTop + mPaddingBottom, lp.height); /// 正式由这些共同作用,然后确定生成了子View的测量规格 // 然后最后计算子View的measure方法 child.measure(childWidthMeasureSpec, childHeightMeasureSpec); }
publicstaticintgetChildMeasureSpec(int spec, int padding, int childDimension) { //父view的测量模式 intspecMode= MeasureSpec.getMode(spec); //父view的大小 intspecSize= MeasureSpec.getSize(spec); //通过父view计算出的子view = 父大小-父控件的内边距(父要求的大小,但子view不一定用这个值) intsize= Math.max(0, specSize - padding); //子view想要的实际大小和模式(需要计算) intresultSize=0; intresultMode=0; //通过父view的MeasureSpec和子view的LayoutParams确定子view的大小 //所以我们根据父布局的specMode // 当父view的模式为EXACITY时,父view强加给子view确切的值 //一般是父view设置为match_parent或者固定值的ViewGroup switch (specMode) { // Parent has imposed an exact size on us case MeasureSpec.EXACTLY: // 当子view的LayoutParams>0,即有确切的值 if (childDimension >= 0) { //子view大小为子自身所赋的值,模式大小为EXACTLY resultSize = childDimension; resultMode = MeasureSpec.EXACTLY; // 当子view的LayoutParams为MATCH_PARENT时(-1) } elseif (childDimension == LayoutParams.MATCH_PARENT) { // Child wants to be our size. So be it. //子view大小为父view大小,模式为EXACTLY resultSize = size; resultMode = MeasureSpec.EXACTLY; } elseif (childDimension == LayoutParams.WRAP_CONTENT) { // Child wants to determine its own size. It can't be // bigger than us. // 当子view的LayoutParams为WRAP_CONTENT时(-2) //子view决定自己的大小,但最大不能超过父view,模式为AT_MOST resultSize = size; resultMode = MeasureSpec.AT_MOST; } break;
// Parent has imposed a maximum size on us // 当父view的模式为AT_MOST时,父view强加给子view一个最大的值。(一般是父view设置为wrap_content) case MeasureSpec.AT_MOST: if (childDimension >= 0) { // Child wants a specific size... so be it resultSize = childDimension; resultMode = MeasureSpec.EXACTLY; } elseif (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; } elseif (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 // 当父view的模式为UNSPECIFIED时,父容器不对view有任何限制,要多大给多大 // 多见于ListView、GridView case MeasureSpec.UNSPECIFIED: // 子view大小为子自身所赋的值 if (childDimension >= 0) { // Child wants a specific size... let him have it resultSize = childDimension; resultMode = MeasureSpec.EXACTLY; } elseif (childDimension == LayoutParams.MATCH_PARENT) { // Child wants to be our size... find out how big it should // be // 因为父view为UNSPECIFIED,所以MATCH_PARENT的话子类大小为0 resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size; resultMode = MeasureSpec.UNSPECIFIED; } elseif (childDimension == LayoutParams.WRAP_CONTENT) { // Child wants to determine its own size.... find out how // big it should be // 因为父view为UNSPECIFIED,所以WRAP_CONTENT的话子类大小为0 resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size; resultMode = MeasureSpec.UNSPECIFIED; } break; } //noinspection ResourceType return MeasureSpec.makeMeasureSpec(resultSize, resultMode); }
// See how tall everyone is. Also remember max width. for (int i = 0; i < count; ++i) { // 获取所有的子View 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). // 遍历所有的子View然后针对每个子View执行measureChildBeforeLayout方法 measureChildBeforeLayout( child,i,widthMeasureSpec,0,heightMeasureSpec, totalWeight == 0 ? mTotalLength : 0); if (oldHeight != Integer.MIN_VALUE) { lp.height = oldHeight; } final int childHeight = child.getMeasuredHeight(); final int totalLength = mTotalLength; // 这样就通过mTotalLength这个变量来存储LinearLayout在竖直方向的初步高度 mTotalLength=Math.max(totalLength,totalLength+childHeight+lp.topMargin + lp.bottomMargin + getNextLocationOffset(child)); }
public static int resolveSizeAndState(int size,int measureSpec,int childMeasuredState) { 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: if (specSize < size) { result = specSize | MEASURED_STATE_TOO_SMALL; } else { result = size; } break; case MeasureSpec.EXACTLY: result = specSize; break; } return result | (childMeasuredState&MEASURED_STATE_MASK); }
public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); if (hasFocus) { int width = view.getMeasuredWidth(); int height = view.getMeasuredHeight(); } }