/** * This is called to find out how big a view should be. The parent * supplies constraint information in the width and height parameters. * 从文档注释可以看出:widthMeasureSpec和heightMeasureSpec是父View对子View尺寸测量的一个约束信息 */ publicfinalvoidmeasure(int widthMeasureSpec, int heightMeasureSpec) { //忽略部分代码... if (forceLayout || needsLayout) { // 忽略部分代码... intcacheIndex= forceLayout ? -1 : mMeasureCache.indexOfKey(key); if (cacheIndex < 0 || sIgnoreMeasureCache) { // measure ourselves, this should set the measured dimension flag back onMeasure(widthMeasureSpec, heightMeasureSpec); mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; } } }
/** * View的onLayout是空实现,ViewGroup需要重写此方法 * 对子View进行布局 * Called from layout when this view should * assign a size and position to each of its children. * */ protectedvoidonLayout(boolean changed, int left, int top, int right, int bottom) { }
/** * A MeasureSpec encapsulates the layout requirements passed from parent to child. * Each MeasureSpec represents a requirement for either the width or the height. * A MeasureSpec is comprised of a size and a mode... */ publicstaticclassMeasureSpec
publicstaticintgetChildMeasureSpec(int spec, int padding, int childDimension) { // 父View的MeasureSpec intspecMode= MeasureSpec.getMode(spec); intspecSize= MeasureSpec.getSize(spec); // 可用空间 intsize= Math.max(0, specSize - padding);
intresultSize=0; intresultMode=0;
switch (specMode) { // 如果父View的specMode是EXACTLY case MeasureSpec.EXACTLY: if (childDimension >= 0) { resultSize = childDimension; resultMode = MeasureSpec.EXACTLY; } elseif (childDimension == LayoutParams.MATCH_PARENT) { // Child wants to be our size. So be it. resultSize = size; resultMode = MeasureSpec.EXACTLY; } 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;
// 如果父View的specMode是AT_MOST 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;
// 如果父View的specMode是UNSPECIFIED case MeasureSpec.UNSPECIFIED: 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 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 resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size; resultMode = MeasureSpec.UNSPECIFIED; } break; } //noinspection ResourceType return MeasureSpec.makeMeasureSpec(resultSize, resultMode); }