一、scheduleTraversals -> performTraversals() 这个方法里面会分别调用一下三个方法
- performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
- performLayout(lp, mWidth, mHeight);
- performDraw();
二、各方法详解
1、 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
此方法内部调用了DecorView的measure方法。其内部会调用onMeasure(widthMeasureSpec, heightMeasureSpec);方法进行回调。我们的测量就是重写这个方法来完成的。
private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
if (mView == null) {
return;
}
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
try {
mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
2、performLayout(lp, mWidth, mHeight);内部会调用layout方法,layout方法内部调用了
onLayout(changed, l, t, r, b);方法。
host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
3、performDraw()
if (!cancelDraw && !newSurface) {
if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
for (int i = 0; i < mPendingTransitions.size(); ++i) {
mPendingTransitions.get(i).startChangingAnimations();
}
mPendingTransitions.clear();
}
// 调用performDraw方法
performDraw();
} else {
if (isViewVisible) {
// Try again 又调用了一次measure layout draw
scheduleTraversals();
} else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
for (int i = 0; i < mPendingTransitions.size(); ++i) {
mPendingTransitions.get(i).endChangingAnimations();
}
mPendingTransitions.clear();
}
}
在27版本中performTraversals在调用performLayout方法时,多了一个参数mReportNextDraw。这个在第一次调用时是false,导致layout没有被调用。但是在reportNextDraw()中将此标志位重新置为true。所以在第二次调用scheduleTraversals();时,会调用performLayout方法。这也就是在27版本调用两次onMeasure,调用一次onLayout方法的原因。