阅读这篇博客之前,假设你已经研究了 View编程(5): 自定义View_01_ApiDemo源码研究 提供的实例。
当时,很奇怪为什么会出现这样的log:(在手机上测试结果,不是在模拟器上。)
D/mark ( 2924): onMeasure() is invoked!
D/mark ( 2924): onMeasure() is invoked!
D/mark ( 2924): onMeasure() is invoked!
D/mark ( 2924): onMeasure() is invoked!
D/mark ( 2924): onMeasure() is invoked!
D/mark ( 2924): onMeasure() is invoked!
D/mark ( 2924): onMeasure() is invoked!
D/mark ( 2924): onMeasure() is invoked!
D/mark ( 2924): onMeasure() is invoked!
百思不得其解,只好再次看源码,找答案。
在博客 View编程(3): invalidate()源码分析 分析过invalidate()源码,从而也分析了 draw()、以及onDraw()方法之间的关系。
其实,onMeasure()这个回调方法与onDraw()差不多,也是通过measure()回调。
先看一下,measure()、onMeasure()方法源码。
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;
}
可以看出两个问题:
1. 该方法是一个final方法,不可以被子类重写。只可以被子类继承。
2. 调用了onMeasure()方法:
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
该方法是一个protected方法,是一个回调方法,一般需要子类去重写。
那么,什么时候调用measure()方法?通过上面分析可以知道,肯定是被View自己调用。究竟如何调用,还得看看invalidate()源码。这里不再赘述。
下面把调用关系草图显示如下,如果有兴趣的话,自己search吧!