一.开始
上篇文章我们已经分析到在performTraversals中,View的performMeasure(),performLayout(),performDraw()方法顺序执行,那我们来详细的看下它们是怎么执行的。
二.performMeasure解析
在ViewRootImpl中,performMeasure是实现为
int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
if (DEBUG_LAYOUT) Log.v(mTag, "Ooops, something changed! mWidth="
+ mWidth + " measuredWidth=" + host.getMeasuredWidth()
+ " mHeight=" + mHeight
+ " measuredHeight=" + host.getMeasuredHeight()
+ " dispatchApplyInsets=" + dispatchApplyInsets);
// Ask host how big it wants to be
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
传入的参数childWidthMeasureSpec,childHeightMeasureSpec为根View,也就是mDecorView的测试参数,我们看下其实现
private static int getRootMeasureSpec(int windowSize, int rootDimension) {
int measureSpec;
switch (rootDimension) {
case ViewGroup.LayoutParams.MATCH_PARENT:
// Window can't resize. Force root view to be windowSize.
measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
break;
case ViewGroup.LayoutParams.WRAP_CONTENT:
// Window can resize. Set max size for root view.
measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
break;
default:
// Window wants to be an exact size. Force root view to be that size.
measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
break;
}
return measureSpec;
}
当匹配父容器时,测试模式为MeasureSpec.EXACTLY,大小为屏幕大小
当包裹父容器时,测量模式为MeasureSpec.AT_MOST,大小为屏幕大小
当为其它情况时,测试模式为MeasureSpec.EXACTLY,大小为mDecorView设置的大小
因为mDecorView为MeasureSpec.EXACTLY,所以我们的Activity默认是屏幕大小
看下makeMeasureSpec的实现
public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size,
@MeasureSpecMode int mode) {
if (sUseBrokenMakeMeasureSpec) {
return size + mode;
} else {
return (size & ~MODE_MASK) | (mode & MODE_MASK);
}
}
通过测量大小和测量模式,组合成了mDecorView的测量规格,mDecorView的测量结束后,我们看下其performMeasure的实现
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);
}
}
继续看下View的measure的实现
public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
...
if (forceLayout || needsLayout) {
// first clears the measured dimension flag
mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET;
resolveRtlPropertiesIfNeeded();
int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key);
if (cacheIndex < 0 || sIgnoreMeasureCache) {
// measure ourselves, this should set the measured dimension flag back
onMeasure(widthMeasureSpec, heightMeasureSpec);
mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
} else {
long value = mMeasureCache.valueAt(cacheIndex);
// Casting a long to int drops the high 32 bits, no mask needed
setMeasuredDimensionRaw((int) (value >> 32), (int) value);
mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
}
...
}
在需要测量的条件满足下,会调用onMeasure(widthMeasureSpec, heightMeasureSpec);我们看下其实现
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
最终setMeasuredDimension传入了测量的宽高。当然顶层mDecorView的实现是一个FrameLayout,其实现了自己的onMeasure方法,这里就不再分析了。
三.performLayout解析
在ViewRootImpl,调用是
performLayout(lp, mWidth, mHeight);
看其方法的实现
private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
int desiredWindowHeight) {
...
final View host = mView;
...
try {
host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
}
}
host即为View,看下View的layout的实现
public void layout(int l, int t, int r, int b) {
if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) {
onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec);
mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
}
int oldL = mLeft;
int oldT = mTop;
int oldB = mBottom;
int oldR = mRight;
boolean changed = isLayoutModeOptical(mParent) ?
setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);
if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
onLayout(changed, l, t, r, b);
}
}
其中调用了onLayout方法,看下其实现
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
}
看到原生的View中onLayout是空实现,具体实现由其实现View实现。
四.performDraw解析
ViewRootImpl的performDraw的实现是
private void performDraw() {
...
boolean canUseAsync = draw(fullRedrawNeeded);
}
draw的实现是
private boolean draw(boolean fullRedrawNeeded) {
...
mAttachInfo.mTreeObserver.dispatchOnDraw();
}
其实现是ViewTreeObserver的dispatchOnDraw方法,看其实现
public final void dispatchOnDraw() {
if (mOnDrawListeners != null) {
mInDispatchOnDraw = true;
final ArrayList<OnDrawListener> listeners = mOnDrawListeners;
int numListeners = listeners.size();
for (int i = 0; i < numListeners; ++i) {
listeners.get(i).onDraw();
}
mInDispatchOnDraw = false;
}
}
最终调用了mDeverView的onDraw方法。