您的位置:首页 > 移动开发 > Android开发

android中View.measure方法的源码注解

2015-12-04 11:56 489 查看
首先来看measure方法的源码注解:

public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
//判断旧的mOldWidthMeasureSpec 是否与新的测量方式相同,只要有一个不同就要重新测量
//对widthMeasureSpec的理解:

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
//通过标志位判断是否执行了setMeasuredDimension()方法
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函数有2个参数,widthMeasureSpec 和 heightMeasureSpec。

onMeasure(widthMeasureSpec, heightMeasureSpec)方法:
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//执行setMeasuredDimension方法
//参数解释:
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}

当我们重写onMeasure时,需要调用setMeasuredDimension来设置自身的mMeasuredWidth和mMeasuredHeight,否则,就会抛出上面那个异常
setMeasuredDimension方法:类似于执行setter方法

protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {
//将测量结果赋值
mMeasuredWidth = measuredWidth;
mMeasuredHeight = measuredHeight;
//添加flag,MEASURED_DIMENSION_SET
mPrivateFlags |= MEASURED_DIMENSION_SET;
}

计算都是在getDefaultSize函数里实现的:

//参数解析:size:大小
//measureSpec:是一个复合的标志位
public static int getDefaultSize(int size, int measureSpec) {
//measureSpec是一个复合的概念:二进制表示:最前的2两位表示:mode;后30位表示尺寸
//关于mode:MeasureSpec.UNSPECIFIED这个是未执行大小:对应于wrap_content
//MeasureSpec.AT_MOST:对应match_parent和fill_parent
//MeasureSpec.EXACTLY:代表确切尺寸
int result = size;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
switch (specMode) {
//未指定大小的情况下:返回建议的尺寸
case MeasureSpec.UNSPECIFIED:
result = size;
break;
//AT_MOST,EXACTLY则返回按照mode测量的尺寸.
case MeasureSpec.AT_MOST:
case MeasureSpec.EXACTLY:
result = specSize;
break;
}
return result;
}


关于getSuggestedMinimumHeight()

protected int getSuggestedMinimumHeight() {
//判断是否有背景,没有的话返回mMinHeight 即控件的最小高度(通过属性获取的)
//如果背景不为空,则返回mMinHeight 或mBackground.getMinimumHeight()
return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight());

}


关于MeasureSpec的源码解析:

public static class MeasureSpec {
//设置mode的移位数
private static final int MODE_SHIFT = 30;
private static final int MODE_MASK  = 0x3 << MODE_SHIFT;
//UNSPECIFIED为32个0
public static final int UNSPECIFIED = 0 << MODE_SHIFT;
//EXACTLY为:01+30个0
public static final int EXACTLY     = 1 << MODE_SHIFT;
//AT_MOST为:10+30个0
public static final int AT_MOST     = 2 << MODE_SHIFT;
public static int makeMeasureSpec(int size, int mode) {
//组建复合的measureSpec
return size + mode;
}
public static int getMode(int measureSpec) {
//取出mode
return (measureSpec & MODE_MASK);
}
public static int getSize(int measureSpec) {
//去除mode,获取size
return (measureSpec & ~MODE_MASK);
}
}

测量总结:

measure(MeasureSpec.UNSPECIFIED,MeasureSpec.UNSPECIFIED)即measure(0,0)返回getSuggestedMinimumWidth()

如果采用MeasureSpec.AT_MOST或者
则舍弃getSuggestedMinimumWidth()得到的尺寸,返回int
specSize =MeasureSpec.getSize(measureSpec);的值MeasureSpec.EXACTLY;这是传入measure()的measureSpec参数,是mode+size,因此采用此两种测量方式需要制定尺寸.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android 源码 view