| @CallSuperpublic void draw(Canvas canvas) {
 final int privateFlags = mPrivateFlags;
 //获取dirty区域是否不透明
 final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE &&
 (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);
 //将flag22位21位设置为off,并且将PFLAG_DRAWN设置为on
 mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
 
 //下面的注释是google对view的draw方法的6步分解注释
 /*
 * 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)
 */
 
 // 第一步,绘制背景,如果需要的话。
 int saveCount;
 // 如果dirty区域是不透明的,则跳过绘制背景。
 if (!dirtyOpaque) {
 drawBackground(canvas);
 }
 
 // 大多数情况(不需要绘制边界阴影的情况)都不需要2和5这两部,跳过
 final int viewFlags = mViewFlags;
 // 是否需要绘制横向边界阴影
 boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;
 // 是否需要绘制竖向向边界阴影
 boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;
 // 不需要绘制横向和竖向阴影,执行3,4,6步
 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)
 */
 // 需要绘制阴影的话,则执行全部2-6的流程,不过这个流程并不常见,而且性能和速度上也不是很优秀。
 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;
 
 // 第二步,保存fading相关的canvas图层信息
 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);
 }
 
 // 第三步,如果不是透明的,则调用onDraw方法进行绘制
 if (!dirtyOpaque) onDraw(canvas);
 
 // 第四步,调用dispatchDraw方法,绘制子View
 dispatchDraw(canvas);
 
 // 第五步,绘制阴影边缘
 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);
 
 // 绘制覆盖物,这个覆盖物在前景图的下面(API18引入)
 if (mOverlay != null && !mOverlay.isEmpty()) {
 mOverlay.getOverlayView().dispatchDraw(canvas);
 }
 
 // 第六步,绘制前景图
 onDrawForeground(canvas);
 }
 
 |