绘制界面的过程大致分为三步
- 计算窗口中所有视图的大小。
- 大小确定了之后,给每个视图分配位置。
- 将确定的视图绘制到屏幕上
Measure的过程主要涉及三个函数
public final void measure(int widthMeasureSpec, int heightMeasureSpec)
protected final void setMeasuredDimension(int measuredWidth, int measuredHeight)
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
measure的本质是把视图布局时使用的相对值转换为具体值的过程,如WRAP_CONTENT,MATCH_PARENT
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);
if ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ||
widthMeasureSpec != mOldWidthMeasureSpec ||
heightMeasureSpec != mOldHeightMeasureSpec) {
// first clears the measured dimension flag
mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET;
resolveRtlPropertiesIfNeeded();
int cacheIndex = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ? -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
setMeasuredDimension((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("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
}
接受两个参数widthMeasureSpec,heightMeasureSpec分别表示宽和高的measureSpec。当父视图对子视图进行measure操作时,需要提供父视图的大小,这个measureSpec就表示这个父视图的宽高。measureSpec是一个32位的int值,高16位保存specMode,低16位保存specSize。
sepcMode有三种:,
- EXACTLY exactly是确定的意思,表示父视图已经为子视图确定好了大小,子视图的大小会严格按照父视图指定的值specSize来确定
- AT_MOST at most,最多,表示子视图的大小可以任意定自己的大小,但最多是specSize中指定的值
- UNSPECIFIED 表示子视图的大小没有限制,一般不常用
mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
参数为childWidthMeasureSpec, childHeightMeasureSpec,而这个两个参数
int childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
int childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
desiredWindowHeight代表窗口希望的大小,一般为窗口本身大小,lp为mWIndowAttributes,而
mWindowAttributes在ViewRoot初始化时创建
public LayoutParams() {
super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
type = TYPE_APPLICATION;
format = PixelFormat.OPAQUE;
}
可以看到lp的width和height默认均为MATCH_PARENT
回到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.
measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
break;
}
return measureSpec;
}
默认measureSpec的mode类型就是EXACTLY,且specSize就等于windowSize。