
绘制是从ViewRootImpl的performTraversals方法开始的
1.ViewRootImpl.performTraversals()
在performTraversals()方法中会调用View.measure。即调用DecorView的measure方法。进一步调用onMeasure方法。接着遍历子View,进行测量,这里就是调用ViewRoot的measure方法。
2.ViewRoot.measure()
ViewRoot.measure()方法也是调用的onMeasure方法。但是ViewRoot是VIewGroup类型,没有实现onMeasure方法。但是系统提供的LinearLayout等方法实际上实现了。因此现在假设我们写了一个布局是垂直排列的LinearLayout里面嵌套了一个TextView.接着我们来看一下LinearLayout的onMeasure方法。
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (mOrientation == VERTICAL) { measureVertical(widthMeasureSpec, heightMeasureSpec); } else { measureHorizontal(widthMeasureSpec, heightMeasureSpec); } }这个方法实际又调用了
measureVertical(widthMeasureSpec, heightMeasureSpec);
方法。
2.我们看一下measureVertical方法。
void measureVertical(int widthMeasureSpec, int heightMeasureSpec) {
<span style="white-space:pre"> </span>。。。
<span style="white-space:pre"> </span>for (int i = 0; i < count; ++i) { final View child = getVirtualChildAt(i);
<span style="white-space:pre"> </span><pre name="code" class="java"><span style="white-space:pre"> </span>measureChildBeforeLayout( child, i, widthMeasureSpec, 0, heightMeasureSpec, totalWeight == 0 ? mTotalLength : 0);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>。。。
<span style="white-space:pre"> </span>setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),heightSizeAndState);
}在这个方法中主要是measureChildBeforeLayout()方法,我们再看一下这个方法。
3.measureChildBeforeLayout()
void measureChildBeforeLayout(View child, int childIndex, int widthMeasureSpec, int totalWidth, int heightMeasureSpec, int totalHeight) { measureChildWithMargins(child, widthMeasureSpec, totalWidth, heightMeasureSpec, totalHeight); }4.measureChildWithMargins()
protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) { final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin + widthUsed, lp.width); final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin + heightUsed, lp.height); child.measure(childWidthMeasureSpec, childHeightMeasureSpec); }在这个方法中,可以看到首先得到了child的MeasureSpec,之后调用child.measure 方法又去测量子View。
5.当子View是诸如TextView之类的控件的时候
会执行如下代码
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); }这里才是真正对控件的宽高进行设置的地方。
6.当测量完成后,会调用ViewGroup的layout方法
@Override public final void layout(int l, int t, int r, int b) { if (!mSuppressLayout && (mTransition == null || !mTransition.isChangingLayout())) { if (mTransition != null) { mTransition.layoutChange(this); } super.layout(l, t, r, b); } else { // record the fact that we noop'd it; request layout when transition finishes mLayoutCalledWhileSuppressed = true; } }这里调用了View的layout,当我们进入View的layout发现又调用了onlayout方法,但是View当中的onLayout是空的,这就意味着子类重写了,因此我们来看一下Linearlayout的onLayout方法
7.Linearlayout.onLayout()
@Override protected void onLayout(boolean changed, int l, int t, int r, int b) { if (mOrientation == VERTICAL) { layoutVertical(l, t, r, b); } else { layoutHorizontal(l, t, r, b); } }
void layoutVertical(int left, int top, int right, int bottom) { for (int i = 0; i < count; i++) { final View child = getVirtualChildAt(i); setChildFrame(child, childLeft, childTop + getLocationOffset(child), childWidth, childHeight);
}
}<pre name="code" class="java"> private void setChildFrame(View child, int left, int top, int width, int height) { child.layout(left, top, left + width, top + height); }最终我们 会看到再次遍历调用child的layout方法。如果child是ViewGroup则会重复上面的方法,直到遍历了所有的View之后才会对自己的位置进行设置。而如果是TextView之类的则最终会调用setFrame方法设置View的宽和高。
8.draw方法
public void draw(Canvas canvas) { final int privateFlags = mPrivateFlags; final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE && (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState); mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN; /* * Draw traversal performs several drawing steps which must be executed * in the appropriate order: * * 1. Draw the background * 2. If necessary, save the canvas' layers to prepare for fading * 3. Draw view's content * 4. Draw children * 5. If necessary, draw the fading edges and restore layers * 6. Draw decorations (scrollbars for instance) */ // Step 1, draw the background, if needed int saveCount; if (!dirtyOpaque) { drawBackground(canvas); } // skip step 2 & 5 if possible (common case) final int viewFlags = mViewFlags; boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0; boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0; if (!verticalEdges && !horizontalEdges) { // Step 3, draw the content if (!dirtyOpaque) onDraw(canvas); // Step 4, draw the children dispatchDraw(canvas); // Overlay is part of the content and draws beneath Foreground if (mOverlay != null && !mOverlay.isEmpty()) { mOverlay.getOverlayView().dispatchDraw(canvas); } // Step 6, draw decorations (foreground, scrollbars) onDrawForeground(canvas); // we're done... return; } /* * Here we do the full fledged routine... * (this is an uncommon case where speed matters less, * this is why we repeat some of the tests that have been * done above) */ boolean drawTop = false; boolean drawBottom = false; boolean drawLeft = false; boolean drawRight = false; float topFadeStrength = 0.0f; float bottomFadeStrength = 0.0f; float leftFadeStrength = 0.0f; float rightFadeStrength = 0.0f; // Step 2, save the canvas' layers int paddingLeft = mPaddingLeft; final boolean offsetRequired = isPaddingOffsetRequired(); if (offsetRequired) { paddingLeft += getLeftPaddingOffset(); } int left = mScrollX + paddingLeft; int right = left + mRight - mLeft - mPaddingRight - paddingLeft; int top = mScrollY + getFadeTop(offsetRequired); int bottom = top + getFadeHeight(offsetRequired); if (offsetRequired) { right += getRightPaddingOffset(); bottom += getBottomPaddingOffset(); } final ScrollabilityCache scrollabilityCache = mScrollCache; final float fadeHeight = scrollabilityCache.fadingEdgeLength; int length = (int) fadeHeight; // clip the fade length if top and bottom fades overlap // overlapping fades produce odd-looking artifacts if (verticalEdges && (top + length > bottom - length)) { length = (bottom - top) / 2; } // also clip horizontal fades if necessary if (horizontalEdges && (left + length > right - length)) { length = (right - left) / 2; } if (verticalEdges) { topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength())); drawTop = topFadeStrength * fadeHeight > 1.0f; bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength())); drawBottom = bottomFadeStrength * fadeHeight > 1.0f; } if (horizontalEdges) { leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength())); drawLeft = leftFadeStrength * fadeHeight > 1.0f; rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength())); drawRight = rightFadeStrength * fadeHeight > 1.0f; } saveCount = canvas.getSaveCount(); int solidColor = getSolidColor(); if (solidColor == 0) { final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG; if (drawTop) { canvas.saveLayer(left, top, right, top + length, null, flags); } if (drawBottom) { canvas.saveLayer(left, bottom - length, right, bottom, null, flags); } if (drawLeft) { canvas.saveLayer(left, top, left + length, bottom, null, flags); } if (drawRight) { canvas.saveLayer(right - length, top, right, bottom, null, flags); } } else { scrollabilityCache.setFadeColor(solidColor); } // Step 3, draw the content if (!dirtyOpaque) onDraw(canvas); // Step 4, draw the children dispatchDraw(canvas); // Step 5, draw the fade effect and restore layers final Paint p = scrollabilityCache.paint; final Matrix matrix = scrollabilityCache.matrix; final Shader fade = scrollabilityCache.shader; if (drawTop) { matrix.setScale(1, fadeHeight * topFadeStrength); matrix.postTranslate(left, top); fade.setLocalMatrix(matrix); p.setShader(fade); canvas.drawRect(left, top, right, top + length, p); } if (drawBottom) { matrix.setScale(1, fadeHeight * bottomFadeStrength); matrix.postRotate(180); matrix.postTranslate(left, bottom); fade.setLocalMatrix(matrix); p.setShader(fade); canvas.drawRect(left, bottom - length, right, bottom, p); } if (drawLeft) { matrix.setScale(1, fadeHeight * leftFadeStrength); matrix.postRotate(-90); matrix.postTranslate(left, top); fade.setLocalMatrix(matrix); p.setShader(fade); canvas.drawRect(left, top, left + length, bottom, p); } if (drawRight) { matrix.setScale(1, fadeHeight * rightFadeStrength); matrix.postRotate(90); matrix.postTranslate(right, top); fade.setLocalMatrix(matrix); p.setShader(fade); canvas.drawRect(right - length, top, right, bottom, p); } canvas.restoreToCount(saveCount); // Overlay is part of the content and draws beneath Foreground if (mOverlay != null && !mOverlay.isEmpty()) { mOverlay.getOverlayView().dispatchDraw(canvas); } // Step 6, draw decorations (foreground, scrollbars) onDrawForeground(canvas); }
- 上一篇 Android面试之类集合问题总结
- 下一篇 Android笔试之JAVA笔试题总结
查看评论