流程圖如下:
看高清圖請下載
對於開頭的方法是調用了ViewRootImpl方法裏的,之所以調這個方法也可通過高清圖進行分析這裏直接從performTraversals方法進行分析
private void performTraversals() {
// cache mView since it is used so much below...
......
if (!mStopped || mReportNextDraw) {
.....
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
.......
if (measureAgain) {
if (DEBUG_LAYOUT) Log.v(mTag,
"And hey let's measure once more: width=" + width
+ " height=" + height);
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
}
layoutRequested = true;
}
}
.......
performLayout(lp, mWidth, mHeight);
......
performDraw();
......
}
private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
try {
mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
通過分析mView是DecorView,它實現繼承了VIew類因此查找measure的方法:
public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
......
onMeasure(widthMeasureSpec, heightMeasureSpec);
......
}
這個onMeasure實現在
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
......
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
......
if (measure) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
查看方法可知調用了父類的onMeasure方法,DecorView也繼承FrameLayout類
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
......
count = mMatchParentChildren.size();
if (count > 1) {
for (int i = 0; i < count; i++) {
final View child = mMatchParentChildren.get(i);
......
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
}
}
通過遍歷的方式將子控件的大小計算出來,如果子控件還是VIewGroup將進行遞歸,也就是說計算控件的大小是通過遞歸遍歷的方式解決的
下面是Layout方法
private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
int desiredWindowHeight) {
......
host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
......
if (numViewsRequestingLayout > 0) {
......
host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
......
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
mInLayout = false;
}
其中host就是DecorView,調用了父類View的方法 public void layout(int l, int t, int r, int b) {
......
if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
onLayout(changed, l, t, r, b);
mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED;
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnLayoutChangeListeners != null) {
ArrayList<OnLayoutChangeListener> listenersCopy =
(ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone();
int numListeners = listenersCopy.size();
for (int i = 0; i < numListeners; ++i) {
listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB);
}
}
}
......
}
這樣會調用Decor的onlayout方法如下:
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
......
}
調用了父類的onlayout方法:
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
layoutChildren(left, top, right, bottom, false /* no force left gravity */);
}
void layoutChildren(int left, int top, int right, int bottom, boolean forceLeftGravity) {
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
......
child.layout(childLeft, childTop, childLeft + width, childTop + height);
}
}
}
通過上面方法可知layout方法也是通過遞歸遍歷的方式來設置view的位置的,這個和計算view的大小的邏輯是一樣的
接下來是view的draw
private void performDraw() {
......
try {
draw(fullRedrawNeeded);
} finally {
mIsDrawing = false;
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
......
}
private void draw(boolean fullRedrawNeeded) {
......
if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)) {
return;
}
}
}
if (animating) {
mFullRedrawNeeded = true;
scheduleTraversals();
}
}
private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
boolean scalingRequired, Rect dirty) {
......
try {
canvas.translate(-xoff, -yoff);
if (mTranslator != null) {
mTranslator.translateCanvas(canvas);
}
canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0);
attachInfo.mSetIgnoreDirtyState = false;
mView.draw(canvas);
......
}
其中的mView是DecorView控件,調用了View中的方法 public void draw(Canvas canvas) {
......
// Step 3, draw the content//繪製自己的內容
if (!dirtyOpaque) onDraw(canvas);
// Step 4, draw the children
dispatchDraw(canvas);//繪製自己的子控件
......
}
@Override//調用的是ViewGroup中的
protected void dispatchDraw(Canvas canvas) {
.....
for (int i = 0; i < childrenCount; i++) {
while (transientIndex >= 0 && mTransientIndices.get(transientIndex) == i) {
final View transientChild = mTransientViews.get(transientIndex);
if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE ||
transientChild.getAnimation() != null) {
more |= drawChild(canvas, transientChild, drawingTime);
}
transientIndex++;
if (transientIndex >= transientCount) {
transientIndex = -1;
}
}
final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
more |= drawChild(canvas, child, drawingTime);
}
}
while (transientIndex >= 0) {
// there may be additional transient views after the normal views
final View transientChild = mTransientViews.get(transientIndex);
if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE ||
transientChild.getAnimation() != null) {
more |= drawChild(canvas, transientChild, drawingTime);
}
transientIndex++;
if (transientIndex >= transientCount) {
break;
}
}
if (preorderedList != null) preorderedList.clear();
// Draw any disappearing views that have animations
if (mDisappearingChildren != null) {
final ArrayList<View> disappearingChildren = mDisappearingChildren;
final int disappearingCount = disappearingChildren.size() - 1;
// Go backwards -- we may delete as animations finish
for (int i = disappearingCount; i >= 0; i--) {
final View child = disappearingChildren.get(i);
more |= drawChild(canvas, child, drawingTime);
}
}
......
}
通過上面最終調用drawChild方法來進行繪製子控件 protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
return child.draw(canvas, this, drawingTime);
}
draw這步也是通過遞歸遍歷的方式進行操作的。