码迷,mamicode.com
首页 > 其他好文 > 详细

4.View绘制分析笔记之onDraw

时间:2016-12-30 10:41:19      阅读:272      评论:0      收藏:0      [点我收藏+]

标签:rsa   sap   全屏   ever   详细介绍   invalid   覆盖   getwidth   put   

上一篇文章我们了解了View的onLayout,那么今天我们来学习Android View绘制三部曲的最后一步,onDraw,绘制。

ViewRootImpl#performDraw

private void performDraw() {

···
final boolean fullRedrawNeeded = mFullRedrawNeeded;
mFullRedrawNeeded = false;

mIsDrawing = true;
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
try {
draw(fullRedrawNeeded);
} finally {
mIsDrawing = false;
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}

···

}

performDraw主要的作用是调用ViewRootImpl#draw方法,并传递一个mFullRedrawNeeded参数,这个参数就是告诉draw方法,是否需要整体重新绘制,所以,我们把重点放在ViewRootImpl#draw这里。

ViewRootImpl#draw

下面代码为draw方法的关键代码

private void draw(boolean fullRedrawNeeded) {
//省略
···
//生成绘制区域
final Rect dirty = mDirty;
//如果需要全屏绘制,则将dirty区域宽高设为全屏
if (fullRedrawNeeded) {
mAttachInfo.mIgnoreDirtyState = true;
dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
}
//省略
···
//调用drawSoftware方法,并传递dirty区域
if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)) {
return;
}
}

ViewRootImpl#drawSoftware

private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
boolean scalingRequired, Rect dirty) {

//通过dirty区域,获取并锁定canvas,后续传给decorView
final Canvas canvas;
try {
final int left = dirty.left;
final int top = dirty.top;
final int right = dirty.right;
final int bottom = dirty.bottom;

canvas = mSurface.lockCanvas(dirty);
} catch (Surface.OutOfResourcesException e) {
handleOutOfResourcesException(e);
return false;
} catch (IllegalArgumentException e) {
mLayoutRequested = true;
return false;
}
//省略
···
//开始调用decorView的draw方法
mView.draw(canvas);
}

View#draw

终于到了View的部分,View的draw方法,答题包括了6个步骤,稍后我们通过源代码进行逐步分析。

@CallSuper
public 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);}

View#drawBackground

这是第一步,绘制背景

private void drawBackground(Canvas canvas) {
final Drawable background = mBackground;
if (background == null) {
return;
}
//如果背景边界发生变化,则重新设置边界大小
setBackgroundBounds();

// 如果设置了硬件加速,则使用 display list 绘制背景
if (canvas.isHardwareAccelerated() && mAttachInfo != null
&& mAttachInfo.mHardwareRenderer != null) {
mBackgroundRenderNode = getDrawableRenderNode(background, mBackgroundRenderNode);

final RenderNode renderNode = mBackgroundRenderNode;
if (renderNode != null && renderNode.isValid()) {
setBackgroundRenderNodeProperties(renderNode);
((DisplayListCanvas) canvas).drawRenderNode(renderNode);
return;
}
}

//获取滑动偏移量,如果有偏移,则先把canvas移动,然后绘制背景,最后再移动回来。
final int scrollX = mScrollX;
final int scrollY = mScrollY;
if ((scrollX | scrollY) == 0) {
background.draw(canvas);
} else {
canvas.translate(scrollX, scrollY);
background.draw(canvas);
canvas.translate(-scrollX, -scrollY);
}
}

ViewGroup#dispatchDraw

这里是第四步,绘制子View,dispatchDraw方法由ViewGroup实现。

protected void dispatchDraw(Canvas canvas) {
boolean usingRenderNodeProperties = canvas.isRecordingFor(mRenderNode);
final int childrenCount = mChildrenCount;
final View[] children = mChildren;
int flags = mGroupFlags;
//查看FLAG_RUN_ANIMATION是否是on,如果是的话,则为子View设置动画,并启动动画
if ((flags & FLAG_RUN_ANIMATION) != 0 && canAnimate()) {
final boolean buildCache = !isHardwareAccelerated();
for (int i = 0; i < childrenCount; i++) {
final View child = children[i];
if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
final LayoutParams params = child.getLayoutParams();
attachLayoutAnimationParameters(child, params, i, childrenCount);
bindLayoutAnimation(child);
}
}

final LayoutAnimationController controller = mLayoutAnimationController;
if (controller.willOverlap()) {
mGroupFlags |= FLAG_OPTIMIZE_INVALIDATE;
}

controller.start();

mGroupFlags &= ~FLAG_RUN_ANIMATION;
mGroupFlags &= ~FLAG_ANIMATION_DONE;

if (mAnimationListener != null) {
mAnimationListener.onAnimationStart(controller.getAnimation());
}
}

int clipSaveCount = 0;
// 对canvas设置padding区域
final boolean clipToPadding = (flags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK;
if (clipToPadding) {
clipSaveCount = canvas.save();
canvas.clipRect(mScrollX + mPaddingLeft, mScrollY + mPaddingTop,
mScrollX + mRight - mLeft - mPaddingRight,
mScrollY + mBottom - mTop - mPaddingBottom);
}

// 我们将启动子View的动画,所以把这里的PFLAG_DRAW_ANIMATION置为off
mPrivateFlags &= ~PFLAG_DRAW_ANIMATION;
mGroupFlags &= ~FLAG_INVALIDATE_REQUIRED;

boolean more = false;
//获取绘图时开始的时间
final long drawingTime = getDrawingTime();

if (usingRenderNodeProperties) canvas.insertReorderBarrier();
final int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();
int transientIndex = transientCount != 0 ? 0 : -1;
// 如果启用硬件加速,那么就不支持view绘制优先级了,硬件内部会处理绘制的先后顺序
final ArrayList<View> preorderedList = usingRenderNodeProperties
? null : buildOrderedChildList();
final boolean customOrder = preorderedList == null
&& isChildrenDrawingOrderEnabled();
for (int i = 0; i < childrenCount; i++) {
//绘制瞬态视图,
//目前瞬态视图的add方法是在两年前android M中加入进来的,目前还是@hide的,
//所以transientIndex是-1,所以这个while循环不会执行到,
//可能这段代码是google为以后的功能做的铺垫。
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;
}
}

//按绘制顺序获取子View index
final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
//通过index获取需要绘制的View,并执行drawChild方法
final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
//绘制子View,下面详细介绍
more |= drawChild(canvas, child, drawingTime);
}
}
//绘制瞬态View,略过,可能会在以后的某个版本中
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();

// 绘制正在消失的View(还没结束动画)
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);
}
}
if (usingRenderNodeProperties) canvas.insertInorderBarrier();

if (debugDraw()) {
onDebugDraw(canvas);
}

if (clipToPadding) {
canvas.restoreToCount(clipSaveCount);
}

// 如果FLAG_INVALIDATE_REQUIRED是on,则调用invalidate刷新
flags = mGroupFlags;

if ((flags & FLAG_INVALIDATE_REQUIRED) == FLAG_INVALIDATE_REQUIRED) {
invalidate(true);
}

//动画结束后发出通知,并擦除缓存
if ((flags & FLAG_ANIMATION_DONE) == 0 && (flags & FLAG_NOTIFY_ANIMATION_LISTENER) == 0 &&
mLayoutAnimationController.isDone() && !more) {
// We want to erase the drawing cache and notify the listener after the
// next frame is drawn because one extra invalidate() is caused by
// drawChild() after the animation is over
mGroupFlags |= FLAG_NOTIFY_ANIMATION_LISTENER;
final Runnable end = new Runnable() {
@Override
public void run() {
notifyAnimationListener();
}
};
post(end);
}
}

View#draw(Canvas canvas, ViewGroup parent, long drawingTime)

这个方法是被ViewGroup调用,让子View来绘制自己的。该方法是View基于 layer type 以及硬件加速来专门处理渲染行为的代码段。

boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated();
/* If an attached view draws to a HW canvas, it may use its RenderNode + DisplayList.
*
* If a view is dettached, its DisplayList shouldn‘t exist. If the canvas isn‘t
* HW accelerated, it can‘t handle drawing RenderNodes.
*/
// 检测是否启动硬件加速
boolean drawingWithRenderNode = mAttachInfo != null
&& mAttachInfo.mHardwareAccelerated
&& hardwareAcceleratedCanvas;

boolean more = false;
final boolean childHasIdentityMatrix = hasIdentityMatrix();
final int parentFlags = parent.mGroupFlags;

if ((parentFlags & ViewGroup.FLAG_CLEAR_TRANSFORMATION) != 0) {
parent.getChildTransformation().clear();
parent.mGroupFlags &= ~ViewGroup.FLAG_CLEAR_TRANSFORMATION;
}

Transformation transformToApply = null;
boolean concatMatrix = false;
final boolean scalingRequired = mAttachInfo != null && mAttachInfo.mScalingRequired;
final Animation a = getAnimation();
if (a != null) {
more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired);
concatMatrix = a.willChangeTransformationMatrix();
if (concatMatrix) {
mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM;
}
transformToApply = parent.getChildTransformation();
} else {
if ((mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_TRANSFORM) != 0) {
// 不再执行动画,全部清除掉
mRenderNode.setAnimationMatrix(null);
mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_TRANSFORM;
}
if (!drawingWithRenderNode
&& (parentFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
final Transformation t = parent.getChildTransformation();
final boolean hasTransform = parent.getChildStaticTransformation(this, t);
if (hasTransform) {
final int transformType = t.getTransformationType();
transformToApply = transformType != Transformation.TYPE_IDENTITY ? t : null;
concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0;
}
}
}

concatMatrix |= !childHasIdentityMatrix;

// 尽早设置PFLAG_DRAWN参数,使invalidate()可以成功调用
mPrivateFlags |= PFLAG_DRAWN;

if (!concatMatrix &&
(parentFlags & (ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS |
ViewGroup.FLAG_CLIP_CHILDREN)) == ViewGroup.FLAG_CLIP_CHILDREN &&
canvas.quickReject(mLeft, mTop, mRight, mBottom, Canvas.EdgeType.BW) &&
(mPrivateFlags & PFLAG_DRAW_ANIMATION) == 0) {
mPrivateFlags2 |= PFLAG2_VIEW_QUICK_REJECTED;
return more;
}
mPrivateFlags2 &= ~PFLAG2_VIEW_QUICK_REJECTED;

if (hardwareAcceleratedCanvas) {
// 清楚PFLAG_INVALIDATED标志位
mRecreateDisplayList = (mPrivateFlags & PFLAG_INVALIDATED) != 0;
mPrivateFlags &= ~PFLAG_INVALIDATED;
}

RenderNode renderNode = null;
Bitmap cache = null;
int layerType = getLayerType(); // TODO: signify cache state with just ‘cache‘ local
if (layerType == LAYER_TYPE_SOFTWARE || !drawingWithRenderNode) {
if (layerType != LAYER_TYPE_NONE) {
// 如果没有RenderNode,则使用SW绘制
layerType = LAYER_TYPE_SOFTWARE;
buildDrawingCache(true);
}
cache = getDrawingCache(true);
}

if (drawingWithRenderNode) {
// 延迟获取Display List,直到animation-driven alpha的值被设置好。
renderNode = updateDisplayListIfDirty();
if (!renderNode.isValid()) {
// 不常见的,略过
renderNode = null;
drawingWithRenderNode = false;
}
}

//下面是对view当前状态的分析,scale、alpha和translate,然后对canvas进行调整。
int sx = 0;
int sy = 0;
if (!drawingWithRenderNode) {
computeScroll();
sx = mScrollX;
sy = mScrollY;
}

final boolean drawingWithDrawingCache = cache != null && !drawingWithRenderNode;
final boolean offsetForScroll = cache == null && !drawingWithRenderNode;

int restoreTo = -1;
if (!drawingWithRenderNode || transformToApply != null) {
restoreTo = canvas.save();
}
if (offsetForScroll) {
canvas.translate(mLeft - sx, mTop - sy);
} else {
if (!drawingWithRenderNode) {
canvas.translate(mLeft, mTop);
}
if (scalingRequired) {
if (drawingWithRenderNode) {
// TODO: Might not need this if we put everything inside the DL
restoreTo = canvas.save();
}
// mAttachInfo cannot be null, otherwise scalingRequired == false
final float scale = 1.0f / mAttachInfo.mApplicationScale;
canvas.scale(scale, scale);
}
}

float alpha = drawingWithRenderNode ? 1 : (getAlpha() * getTransitionAlpha());
if (transformToApply != null
|| alpha < 1
|| !hasIdentityMatrix()
|| (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) {
if (transformToApply != null || !childHasIdentityMatrix) {
int transX = 0;
int transY = 0;

if (offsetForScroll) {
transX = -sx;
transY = -sy;
}

if (transformToApply != null) {
if (concatMatrix) {
if (drawingWithRenderNode) {
renderNode.setAnimationMatrix(transformToApply.getMatrix());
} else {
// Undo the scroll translation, apply the transformation matrix,
// then redo the scroll translate to get the correct result.
canvas.translate(-transX, -transY);
canvas.concat(transformToApply.getMatrix());
canvas.translate(transX, transY);
}
parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION;
}

float transformAlpha = transformToApply.getAlpha();
if (transformAlpha < 1) {
alpha *= transformAlpha;
parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION;
}
}

if (!childHasIdentityMatrix && !drawingWithRenderNode) {
canvas.translate(-transX, -transY);
canvas.concat(getMatrix());
canvas.translate(transX, transY);
}
}

// Deal with alpha if it is or used to be <1
if (alpha < 1 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) {
if (alpha < 1) {
mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_ALPHA;
} else {
mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_ALPHA;
}
parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION;
if (!drawingWithDrawingCache) {
final int multipliedAlpha = (int) (255 * alpha);
if (!onSetAlpha(multipliedAlpha)) {
if (drawingWithRenderNode) {
renderNode.setAlpha(alpha * getAlpha() * getTransitionAlpha());
} else if (layerType == LAYER_TYPE_NONE) {
canvas.saveLayerAlpha(sx, sy, sx + getWidth(), sy + getHeight(),
multipliedAlpha);
}
} else {
// Alpha is handled by the child directly, clobber the layer‘s alpha
mPrivateFlags |= PFLAG_ALPHA_SET;
}
}
}
} else if ((mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) {
onSetAlpha(255);
mPrivateFlags &= ~PFLAG_ALPHA_SET; } if (!drawingWithRenderNode) { // apply clips directly, since RenderNode won‘t do it for this draw if ((parentFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0 && cache == null) { if (offsetForScroll) { canvas.clipRect(sx, sy, sx + getWidth(), sy + getHeight()); } else { if (!scalingRequired || cache == null) { canvas.clipRect(0, 0, getWidth(), getHeight()); } else { canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight()); } } } if (mClipBounds != null) { // clip bounds ignore scroll canvas.clipRect(mClipBounds); } } // 这里调用子View的draw方法,并将调整好的canvas传进去 if (!drawingWithDrawingCache) { if (drawingWithRenderNode) { mPrivateFlags &= ~PFLAG_DIRTY_MASK; ((DisplayListCanvas) canvas).drawRenderNode(renderNode); } else { // Fast path for layouts with no backgrounds if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { mPrivateFlags &= ~PFLAG_DIRTY_MASK; dispatchDraw(canvas); } else { draw(canvas); } } } // 如果是cache模式,则利用cache else if (cache != null) { mPrivateFlags &= ~PFLAG_DIRTY_MASK; if (layerType == LAYER_TYPE_NONE || mLayerPaint == null) { // no layer paint, use temporary paint to draw bitmap Paint cachePaint = parent.mCachePaint; if (cachePaint == null) { cachePaint = new Paint(); cachePaint.setDither(false); parent.mCachePaint = cachePaint; } cachePaint.setAlpha((int) (alpha * 255)); canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint); } else { // use layer paint to draw the bitmap, merging the two alphas, but also restore int layerPaintAlpha = mLayerPaint.getAlpha(); if (alpha < 1) { mLayerPaint.setAlpha((int) (alpha * layerPaintAlpha)); } canvas.drawBitmap(cache, 0.0f, 0.0f, mLayerPaint); if (alpha < 1) { mLayerPaint.setAlpha(layerPaintAlpha); } } } if (restoreTo >= 0) { canvas.restoreToCount(restoreTo); } if (a != null && !more) { if (!hardwareAcceleratedCanvas && !a.getFillAfter()) { onSetAlpha(255); } parent.finishAnimatingView(this, a); } if (more && hardwareAcceleratedCanvas) { if (a.hasAlpha() && (mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { // alpha animations should cause the child to recreate its display list invalidate(true); } } mRecreateDisplayList = false; return more;}

到这里,整个View及子View的绘制的调用就基本完成了,剩下的就交给各个View的onDraw方法去实现不同的绘制。

时序图

技术分享图为View绘制时序图

小结

View的绘制大体是6步来进行。

  1. 绘制背景
  2. 保存fade canvas信息
  3. 调用onDraw
  4. dispatchDraw,遍历绘制子View
  5. 绘制fade
  6. 绘制前景

源码中还有不少涉及到硬件加速、RenderNode、display list、动画的代码,后续会专门进行研究。

到这篇文章截止,View视图三部曲就结束了,感谢阅读。

系列文章

Android 视图及View绘制分析笔记之setContentView
View绘制分析笔记之onMeasure
View绘制分析笔记之onLayout
View绘制分析笔记之onDraw

4.View绘制分析笔记之onDraw

标签:rsa   sap   全屏   ever   详细介绍   invalid   覆盖   getwidth   put   

原文地址:http://www.cnblogs.com/dubo-/p/6235755.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!