回顾:上篇我们总结了,UI绘制入口,最终进入到DecorView相关的ViewRootImpl类中,调用questLayout()方法,最终调用performMeasure,performLayout,performDraw实现布局绘制,那么我们先来分析performMeasure
if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
|| mHeight != host.getMeasuredHeight() || contentInsetsChanged ||
updatedConfiguration) {
int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
if (DEBUG_LAYOUT) Log.v(mTag, "Ooops, something changed! mWidth="
+ mWidth + " measuredWidth=" + host.getMeasuredWidth()
+ " mHeight=" + mHeight
+ " measuredHeight=" + host.getMeasuredHeight()
+ " coveredInsetsChanged=" + contentInsetsChanged);
// Ask host how big it wants to be
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
// Implementation of weights from WindowManager.LayoutParams
// We just grow the dimensions as needed and re-measure if
// needs be
int width = host.getMeasuredWidth();
int height = host.getMeasuredHeight();
可以看到performMeasure传进来宽、高的参数,我们跟进
mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
继续跟进发现已经进入View的measure方法
public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
boolean optical = isLayoutModeOptical(this);
if (optical != isLayoutModeOptical(mParent)) {
Insets insets = getOpticalInsets();
int oWidth = insets.left + insets.right;
int oHeight = insets.top + insets.bottom;
widthMeasureSpec = MeasureSpec.adjust(widthMeasureSpec, optical ? -oWidth : oWidth);
heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight);
}
// Suppress sign extension for the low bytes
long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL;
if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2);
final boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT;
// Optimize layout by avoiding an extra EXACTLY pass when the view is
// already measured as the correct size. In API 23 and below, this
// extra pass is required to make LinearLayout re-distribute weight.
final boolean specChanged = widthMeasureSpec != mOldWidthMeasureSpec
|| heightMeasureSpec != mOldHeightMeasureSpec;
final boolean isSpecExactly = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY
&& MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY;
final boolean matchesSpecSize = getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec)
&& getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec);
final boolean needsLayout = specChanged
&& (sAlwaysRemeasureExactly || !isSpecExactly || !matchesSpecSize);
if (forceLayout || needsLayout) {
// first clears the measured dimension flag
mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET;
resolveRtlPropertiesIfNeeded();
int cacheIndex = 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;
} else {
long value = mMeasureCache.valueAt(cacheIndex);
// Casting a long to int drops the high 32 bits, no mask needed
setMeasuredDimensionRaw((int) (value >> 32), (int) value);
mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
}
// flag not set, setMeasuredDimension() was not invoked, we raise
// an exception to warn the developer
if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) {
throw new IllegalStateException("View with id " + getId() + ": "
+ getClass().getName() + "#onMeasure() did not set the"
+ " measured dimension by calling"
+ " setMeasuredDimension()");
}
mPrivateFlags |= PFLAG_LAYOUT_REQUIRED;
}
mOldWidthMeasureSpec = widthMeasureSpec;
mOldHeightMeasureSpec = heightMeasureSpec;
mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 |
(long) mMeasuredHeight & 0xffffffffL); // suppress sign extension
}
这里面我们看到cacheIndex
先去缓存里去找有没有这个值
int cacheIndex = 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;
} else {
long value = mMeasureCache.valueAt(cacheIndex);
// Casting a long to int drops the high 32 bits, no mask needed
setMeasuredDimensionRaw((int) (value >> 32), (int) value);
mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
}
这里判断没有key值的话执行onMeasure方法,有值的话执行setMeasuredDimensionRaw方法,我们看下onMeasure方法
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
发现里面根据测量规则,获取宽高,最终调用了setMeasuredDimension方法,继续跟进
protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {
boolean optical = isLayoutModeOptical(this);
if (optical != isLayoutModeOptical(mParent)) {
Insets insets = getOpticalInsets();
int opticalWidth = insets.left + insets.right;
int opticalHeight = insets.top + insets.bottom;
measuredWidth += optical ? opticalWidth : -opticalWidth;
measuredHeight += optical ? opticalHeight : -opticalHeight;
}
setMeasuredDimensionRaw(measuredWidth, measuredHeight);
}
发现最终还是调用了setMeasuredDimensionRaw方法,最终测量结束,但是这是在View中,我们的布局可能是ViewGroup,我们看一下DecorView,他的父类是FrameLayout,我们看一下onMeasure方法
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int count = getChildCount();
...
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (mMeasureAllChildren || child.getVisibility() != GONE) {
measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
}
}
...
setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
resolveSizeAndState(maxHeight, heightMeasureSpec,
childState << MEASURED_HEIGHT_STATE_SHIFT));
...
count = mMatchParentChildren.size();
if (count > 1) {
for (int i = 0; i < count; i++) {
...
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
}
}
发现是遍历子View然后测量,接下来详细分析如何测量,首先我们去看一个类MeasureSpec
ublic static class MeasureSpec {
private static final int MODE_SHIFT = 30;
//3左移30位
private static final int MODE_MASK = 0x3 << MODE_SHIFT;
/**
* Measure specification mode: The parent has not imposed any constraint
* on the child. It can be whatever size it wants.
*/
//0左移30位
public static final int UNSPECIFIED = 0 << MODE_SHIFT;
/**
* Measure specification mode: The parent has determined an exact size
* for the child. The child is going to be given those bounds regardless
* of how big it wants to be.
*/
//1左移30位
public static final int EXACTLY = 1 << MODE_SHIFT;
/**
* Measure specification mode: The child can be as large as it wants up
* to the specified size.
*/
//2左移30位
public static final int AT_MOST = 2 << MODE_SHIFT;
//生成测量规则打包结果包含测量规则和size
public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size,
@MeasureSpecMode int mode) {
if (sUseBrokenMakeMeasureSpec) {
return size + mode;
} else {
return (size & ~MODE_MASK) | (mode & MODE_MASK);
}
}
//获取测量规则
public static int getMode(int measureSpec) {
//noinspection ResourceType
return (measureSpec & MODE_MASK);
}
public static int getSize(int measureSpec) {
return (measureSpec & ~MODE_MASK);
}
}
下面我们分析他们如何计算
MODE_MASK: 11000000000000000000000000000000
UNSPECIFIED: 00000000000000000000000000000000
EXACTLY: 01000000000000000000000000000000
AT_MOST: 10000000000000000000000000000000
看到它们是32位的二进制数,前面两位代表测量模式,后面30位代表测量的size,我们看下如何生成测量规则
// Older apps may need this compatibility hack for measurement.
sUseBrokenMakeMeasureSpec = targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR1;
//这里就是判断当前的版本号<= 17(android4.2)
if (sUseBrokenMakeMeasureSpec) {
return size + mode;
} else {
return (size & ~MODE_MASK) | (mode & MODE_MASK);
}
size + mode
,比如测量规则为AT_MOST
,size大小为16表示为二进制为1100
,转为32位二进制就是00000000000000000000000000001100
size: 00000000000000000000000000001100
AT_MOST: 10000000000000000000000000000000
//下面就是size+mode相加的值 前面两位10就是测量规则,后面30位就是测量的大小
value: 10000000000000000000000000001100
我们看下(size & ~MODE_MASK) | (mode & MODE_MASK)
如何计算以及计算结果mode = AT_MOST
size: 00000000000000000000000000001100
MODE_MASK: 11000000000000000000000000000000
~MODE_MASK: 00111111111111111111111111111111
AT_MOST: 10000000000000000000000000000000
//size & ~MODE_MASK 与运算只有相同位置都为1则结果为1
value1: 00000000000000000000000000001100
//mode & MODE_MASK
value2: 10000000000000000000000000000000
// value1 | value2 或运算相同位置只要有1就为1
endValue: 10000000000000000000000000001100
对比上面我们发现两种方式获取的结果都为10000000000000000000000000001100
,
我们再看下解包方法getModemeasureSpec & MODE_MASK
最终获取测量规则Mode
MODE_MASK: 11000000000000000000000000000000
MeasureSpec: 10000000000000000000000000001100
//measureSpec & MODE_MASK
value: 10000000000000000000000000000000
最终测量模式Mode就是10000000000000000000000000000000
,然后我们看getSize方法measureSpec & ~MODE_MASK
MeasureSpec: 10000000000000000000000000001100
~MODE_MASK: 00111111111111111111111111111111
//measureSpec & ~MODE_MASK
value: 00000000000000000000000000001100
最终我们拿到的size值为00000000000000000000000000001100
。现在我们了解到最终32位的二进制前两位代表测量规则,后两位代表测量的size,size最大值为111111111111111111111111111111
=1073741823,但实际中我们用不到,我们看下View里面的
//该16进制转化为二进制
public static final int MEASURED_SIZE_MASK = 0x00ffffff;
public final int getMeasuredWidth() {
return mMeasuredWidth & MEASURED_SIZE_MASK;
}
0x00ffffff: 00000000111111111111111111111111
该值为16777215,就是我们现在Android使用的最大值,前面预留了6位可以扩容位。然后我们回到ViewRootImpl类中找到我们的performMeasure传参
//mWidth、mHeight表示屏幕的尺寸lp.width、lp.height表示decorView自己的尺寸
int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
if (DEBUG_LAYOUT) Log.v(mTag, "Ooops, something changed! mWidth="
+ mWidth + " measuredWidth=" + host.getMeasuredWidth()
+ " mHeight=" + mHeight
+ " measuredHeight=" + host.getMeasuredHeight()
+ " coveredInsetsChanged=" + contentInsetsChanged);
// Ask host how big it wants to be
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
我们看一下getRootMeasureSpec方法
private static int getRootMeasureSpec(int windowSize, int rootDimension) {
int measureSpec;
switch (rootDimension) {
//这里发现如果布局为MATCH_PARENT对应的模式为EXACTLY
case ViewGroup.LayoutParams.MATCH_PARENT:
// Window can't resize. Force root view to be windowSize.
measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
break;
//如果布局为WRAP_CONTENT,对应的模式为AT_MOST
case ViewGroup.LayoutParams.WRAP_CONTENT:
// Window can resize. Set max size for root view.
measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
break;
default:
//默认为EXACTLY
// Window wants to be an exact size. Force root view to be that size.
measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
break;
}
return measureSpec;
}
然后我们继续进入performMeasure方法,最终进入measure方法
public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
boolean optical = isLayoutModeOptical(this);
if (optical != isLayoutModeOptical(mParent)) {
Insets insets = getOpticalInsets();
int oWidth = insets.left + insets.right;
int oHeight = insets.top + insets.bottom;
//这里判断view的偏移量
widthMeasureSpec = MeasureSpec.adjust(widthMeasureSpec, optical ? -oWidth : oWidth);
heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight);
}
// Suppress sign extension for the low bytes
//这里的key是从mMeasureCache取数据
long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL;
if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2);
final boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT;
// Optimize layout by avoiding an extra EXACTLY pass when the view is
// already measured as the correct size. In API 23 and below, this
// extra pass is required to make LinearLayout re-distribute weight.
final boolean specChanged = widthMeasureSpec != mOldWidthMeasureSpec
|| heightMeasureSpec != mOldHeightMeasureSpec;
final boolean isSpecExactly = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY
&& MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY;
final boolean matchesSpecSize = getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec)
&& getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec);
final boolean needsLayout = specChanged
&& (sAlwaysRemeasureExactly || !isSpecExactly || !matchesSpecSize);
if (forceLayout || needsLayout) {
// first clears the measured dimension flag
mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET;
resolveRtlPropertiesIfNeeded();
int cacheIndex = 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;
} else {
long value = mMeasureCache.valueAt(cacheIndex);
// Casting a long to int drops the high 32 bits, no mask needed
setMeasuredDimensionRaw((int) (value >> 32), (int) value);
mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
}
// flag not set, setMeasuredDimension() was not invoked, we raise
// an exception to warn the developer
if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) {
throw new IllegalStateException("View with id " + getId() + ": "
+ getClass().getName() + "#onMeasure() did not set the"
+ " measured dimension by calling"
+ " setMeasuredDimension()");
}
mPrivateFlags |= PFLAG_LAYOUT_REQUIRED;
}
mOldWidthMeasureSpec = widthMeasureSpec;
mOldHeightMeasureSpec = heightMeasureSpec;
mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 |
(long) mMeasuredHeight & 0xffffffffL); // suppress sign extension
}
这里我们分析keylong key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL
这里就是将widthMeasureSpec往前移动32位然后再把heightMeasureSpec添加到后面的32位组成一个64位的long类型,
然后mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 |(long) mMeasuredHeight & 0xffffffffL);
存放的时候跟key的算法一样,然后去值的时候setMeasuredDimensionRaw((int) (value >> 32), (int) value)
把该值(64位long类型)往后移动32位然后转换成int类型获取到宽,然后把原来的值直接转换为int,前面32位就没了,就获取到height值,这样就用一个long值就存储了宽和高。
子View测量相关
我们发现measure方法是一个final修饰的方法,所以不能被重写,那么我们只能重写onMeasure方法。因为不同控件布局不同所以我们自定义View要重写onMeasure方法。
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
这里通过getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec)
我们分析下getSuggestedMinimumWidth
protected int getSuggestedMinimumWidth() {
//这里会让控件和背景比较哪个值大返回谁
return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());
}
再来看下getDefaultSize方法
public static int getDefaultSize(int size, int measureSpec) {
//这里的size是子View大小
int result = size;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
switch (specMode) {
//判断如果父类的测量模式是无规则的则返回子View的大小
case MeasureSpec.UNSPECIFIED:
result = size;
break;
//判断如果父容器的测量模式是AT_MOST、EXACTLY则返回父View的测量值
case MeasureSpec.AT_MOST:
case MeasureSpec.EXACTLY:
result = specSize;
break;
}
return result;
}
但是到目前我们发现只是View在测量,那么它的父类做了哪些操作呢。我们进入FrameLayout查看onMeasure方法
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int count = getChildCount();
//看到在ViewGroup的onMeasure中判断如果父容器的测量规则有一个不为EXACTLY则为false
final boolean measureMatchParentChildren =
MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY ||
MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY;
mMatchParentChildren.clear();
int maxHeight = 0;
int maxWidth = 0;
int childState = 0;
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (mMeasureAllChildren || child.getVisibility() != GONE) {
//子View测量完
measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
maxWidth = Math.max(maxWidth,
child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
maxHeight = Math.max(maxHeight,
child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
childState = combineMeasuredStates(childState, child.getMeasuredState());
if (measureMatchParentChildren) {
//这里子View如果用到MATCH_PARENT会添加到集合中
if (lp.width == LayoutParams.MATCH_PARENT ||
lp.height == LayoutParams.MATCH_PARENT) {
mMatchParentChildren.add(child);
}
}
}
}
。。。
//这里去遍历集合,再去测量子View
count = mMatchParentChildren.size();
if (count > 1) {
for (int i = 0; i < count; i++) {
...
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
}
}
上面我们发现for循环获取当前子View然后measureChildWithMargins
去测量,然后再去判断子View是否用到MATCH_PARENT
,如果用到了并且父View的测量规则都不是EXACTLY,那么再去第二次测量子View,所以这里我们要注意,尽量避免子View二次测量,下面我们看下子View第一次测量
protected void measureChildWithMargins(View child,
int parentWidthMeasureSpec, int widthUsed,
int parentHeightMeasureSpec, int heightUsed) {
//获取子View的MarginLayoutParams
final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
//这里拿到父View的pading值以及子View的Margin值去获取对应的测量宽高parentWidthMeasureSpec是父View的测量值
final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
+ widthUsed, lp.width);
final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
+ heightUsed, lp.height);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
我们进入getChildMeasureSpec
public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
// 这里拿到父容器的测量模式和父容器大小
int specMode = MeasureSpec.getMode(spec);
int specSize = MeasureSpec.getSize(spec);
//父View大小减去padding就是子View大小
int size = Math.max(0, specSize - padding);
int resultSize = 0;
int resultMode = 0;
switch (specMode) {
// Parent has imposed an exact size on us
//父容器为EXACTLY
case MeasureSpec.EXACTLY:
if (childDimension >= 0) {
resultSize = childDimension;
resultMode = MeasureSpec.EXACTLY;
} else if (childDimension == LayoutParams.MATCH_PARENT) {
// Child wants to be our size. So be it.
resultSize = size;
resultMode = MeasureSpec.EXACTLY;
}
//子容器为WRAP_CONTENT,则返回值大小为父容器大小,测量规则为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;
}
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
resultSize = childDimension;
resultMode = MeasureSpec.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;
} 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;
}
break;
// Parent asked to see how big we want to be
case MeasureSpec.UNSPECIFIED:
if (childDimension >= 0) {
// Child wants a specific size... let him have it
resultSize = childDimension;
resultMode = MeasureSpec.EXACTLY;
} else if (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;
} else if (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);
}
根据上面我们总结View的测量规则是由父容器的MeasureSpec和自身的LayoutParams决定

最终再去测量父容器的宽高设值,最终完成测量