canvas如何把图像绘制到准确位置

<pre style="background-color:#ffffff;color:#000000;font-family:'宋体';font-size:9.0pt;">父类调用子类的方法并传递canvas对象
从这个方法开始就能清楚知道canvas如何设置的,因为每一层的绘制流程都一样;


<pre name="code" class="java"><pre style="background-color:#ffffff;color:#000000;font-family:'宋体';font-size:9.0pt;"><pre name="code" class="java">/**
 * This method is called by ViewGroup.drawChild() to have each child view draw itself.
 *
 * This is where the View specializes rendering behavior based on layer type,
 * and hardware acceleration.
 */
boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
 
 
 ............................ 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); } } 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); } } } else if (cache != null) { mPrivateFlags &= ~PFLAG_DIRTY_MASK; if (layerType == LAYER_TYPE_NONE) { // 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(); mLayerPaint.setAlpha((int) (alpha * layerPaintAlpha)); canvas.drawBitmap(cache, 0.0f, 0.0f, mLayerPaint); 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; } 
 


canvas.translate(mLeft - sx, mTop - sy); 完成canvas的基准坐标移动;

动画的一些细节;

//这个是裁剪绘制区域;

if (offsetForScroll) {

canvas.clipRect(sx, sy, sx + getWidth(), sy + getHeight());

}

//调用自身的绘制方法

dispatchDraw(Canvas)或draw(canvas);

跳到draw方法中:

说明:

/*
 * 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)
 */
首先绘制背景:

drawBackground(canvas);
方法中代码片段:
   if ((scrollX | scrollY) == 0) {
            background.draw(canvas);
        } else {
            canvas.translate(scrollX, scrollY);
            background.draw(canvas);
            canvas.translate(-scrollX, -scrollY);
        }
可以看到:canvas首先要把基准坐标移动到滚动之前的位置;

略过处理渐变等的一些细节,最终分发给孩子的代码:
dispatchDraw(canvas);

从上面可以知道这个canvas对象的坐标:把mScrollX,mScrollY算进去了;

--------------------------------------------------------------------
总结:每一个父View传递给子View的Canvas是 经过父view的mLeft和mTop与scrollX,scrollY计算translate的canvas;




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值