您的位置:首页 > 其它

普通View的measure流程

2016-06-24 00:56 225 查看
对于普通的view,其测量在ViewGroup中的measureChildWithMargins函数中调用child view的measure开始测量。

1:从measure函数开始

public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
if ((mPrivateFlags & FORCE_LAYOUT) == FORCE_LAYOUT ||
widthMeasureSpec != mOldWidthMeasureSpec ||
heightMeasureSpec != mOldHeightMeasureSpec) {

// first clears the measured dimension flag
mPrivateFlags &= ~MEASURED_DIMENSION_SET;

if (ViewDebug.TRACE_HIERARCHY) {
ViewDebug.trace(this, ViewDebug.HierarchyTraceType.ON_MEASURE);
}

// measure ourselves, this should set the measured dimension flag back
onMeasure(widthMeasureSpec, heightMeasureSpec);

// flag not set, setMeasuredDimension() was not invoked, we raise
// an exception to warn the developer
if ((mPrivateFlags & MEASURED_DIMENSION_SET) != MEASURED_DIMENSION_SET) {
throw new IllegalStateException("onMeasure() did not set the"
+ " measured dimension by calling"
+ " setMeasuredDimension()");
}

mPrivateFlags |= LAYOUT_REQUIRED;
}

mOldWidthMeasureSpec = widthMeasureSpec;
mOldHeightMeasureSpec = heightMeasureSpec;
}


官方关于此函数的说明:measure函数用来计算一个view的尺寸,其传入的参数为parentView对此view的宽/高限制信息。实际的尺寸测量将会调用onMeasure来完成,因此,子类必须重写onMeasure函数。

通过measure函数的源码我们也可以知道:首先,它是final的,所以不可以重写;其次,它主要是对传入的parentView的宽高限制信息进行了是否与上一次的相同的判断,若是相同则不调用onMeasure重新测量;

2:measure ——> onMeasure函数

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}


通过其代码,我们可以知道主要用了这三个函数,我们一一分析:

2.1:getSuggestedMinimumWidth函数:返回android:minWidth和背景宽度二者之间的最大值

protected int getSuggestedMinimumWidth() {
int suggestedMinWidth = mMinWidth; //mMinWidth对应android:minWidth属性所指定的值,如果它没有指定,那么默认为0

if (mBGDrawable != null) {   //如果设置了背景
final int bgMinWidth = mBGDrawable.getMinimumWidth(); //背景的宽度,如果是ShapeDrawable那么为0,如果是BitmapDrawable则有原始宽高
if (suggestedMinWidth < bgMinWidth) {  //如果设定的最小值小于背景图片宽度,那么设定最小值为背景图片宽度
suggestedMinWidth = bgMinWidth;
}
}

return suggestedMinWidth;
}


2.2:getDefaultSize:如果measureSpec没有限定则返回size,否则返回measureSpec中的size

public static int getDefaultSize(int size, int 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;
}


到此:我们可以总结getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec)的逻辑:如果parentView对尺寸没有限制(即parentView的模式为UNSPECIFIED),那么将返回view的suggested最小值,否则返回parentView指定的尺寸。getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)类似。

2.3 setMeasuredDimension:很简单,设置测量的宽高(注意不是view实际的宽高,实际的宽高要等layout完成之后才确定,虽然几乎全部就是measure后的宽高)

protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {
mMeasuredWidth = measuredWidth;
mMeasuredHeight = measuredHeight;

mPrivateFlags |= MEASURED_DIMENSION_SET;
}


至此,关于onMeasure函数分析结束。

===================================================================

http://www.cnblogs.com/willhua/

===================================================================
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: