Measure的具体流程:确定View的测量宽/高
1、 单个view的绘制流程

measure()
/**
* a. 绘制的入口
* b. measure() 是final方法,即子类不能复写
* @param widthMeasureSpec Horizontal space requirements as imposed by the
* parent
* @param heightMeasureSpec Vertical space requirements as imposed by the
* parent
**/
public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
// width/heightMeasureSpec:View的宽 / 高测量规格
...
if (forceLayout || needsLayout) {
...
if (cacheIndex < 0 || sIgnoreMeasureCache) {
// measure ourselves, this should set the measured dimension flag back
onMeasure(widthMeasureSpec, heightMeasureSpec);
} else { ... }
}
}
onMeasure()
/**
* a. 计算视图大小:根据View宽 / 高的测量规格计算View的宽 / 高值:getDefaultSize()
* b. 存储测量后的View宽 / 高:setMeasuredDimension()
**/
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// width/heightMeasureSpec:View的宽 / 高测量规格
// getDefaultSize(默认值,测量规格)
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
setMeasuredDimension()
// 存储测量后的View宽 / 高
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);
}
private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) {
//传递测量后的子View的宽 / 高给环境变量mMeasuredWidth/Hegiht
mMeasuredWidth = measuredWidth;
mMeasuredHeight = measuredHeight;
mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET;
}
getDefaultSize()
/**
*a. 测量模式为UNSPECIFIED,返回默认大小
*b. 测量模式为AT_MOST,EXACTLY时,返回view测量后的宽 / 高值
**/
public static int getDefaultSize(int size, int measureSpec) {
// size:默认大小
// measureSpec:宽/高的测量规格(模式&测量大小)
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:
case MeasureSpec.EXACTLY:
result = specSize;
break;
}
return result;
}
A. specSize
是View
测量后的大小,非最终大小。最终大小是在layout阶段确定,但几乎所有情况下View
的测量大小和最终大小相等。
B. 对于UNSPECIFIED
这种情况,一般用于系统内部的测量过程,宽 / 高为getSuggestedMinimumWidth()/Height()
的返回值。
getSuggestedMinimumWidth()
protected int getSuggestedMinimumWidth() {
return (mBackground == null) ?
mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());
}
//getSuggestedMinimumHeight()同理
A. 若View
没有设置背景,View
的宽度为mMinWidh
a. 其中mMinWidth
为android:minWidth
属性所指定的值。
b. 若android:minWidth
不指定,默认为0.
B. 若View
设置了背景,View
的宽度为max(mMinWidth, mBackground.getMinimumWidth())
-
Drawble
的getMinimumWidth()
public int getMinimumWidth() {
final int intrinsicWidth = getIntrinsicWidth();
return intrinsicWidth > 0 ? intrinsicWidth : 0;
}
//getSuggestedMinimumHeight()同理
A. mBackground.getMinimumWidth()
的大小 = 背景图Drawable
的原始宽度
B. 若无原始宽度,则为0;
注:BitmapDrawable
有原始宽度,而ShapeDrawable
没有
网友评论