阅读这篇博客之前,假设你已经研究了 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吧!