我在android中进行图像注释,并在其中添加了缩放功能。因此,现在当我缩放图像并在之后进行任何注释时,它不在我触摸屏幕的那一点上,而不是像原始图像那样(Unzoomied image)。
onDraw方法
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
onDrawReady = true;
imageRenderedAtLeastOnce = true;
canvas.concat(matrix);
for (DrawObject d : paths) {
if (d.getType() == MODE_DRAWING) {
canvas.drawPath(d.getPair().first, d.getPair().second);
} else if (d.getType() == MODE_TEXT) {
canvas.drawText(d.getText(), d.getX(), d.getY(), d.getPair().second);
} else if (d.getType() == MODE_ARROW) {
canvas.drawLine(d.getStartX(), d.getStartY(), d.getX(), d.getY(), d.getPair().second);
fillArrow(canvas, d.getStartX(), d.getStartY(), d.getX(), d.getY(), d.getPair().second);
} else if (d.getType() == MODE_CIRCLE) {
RectF oval2 = new RectF(d.getStartX(), d.getStartY(), d.getX(), d.getY());
canvas.drawOval(oval2, d.getPair().second);
} else if (d.getType() == MODE_RECTANGLE) {
canvas.drawRect(d.getStartX(), d.getStartY(), d.getX(), d.getY(), d.getPair().second);
} else if (d.getType() == MODE_ERASE) {
canvas.drawPath(d.getPair().first, d.getPair().second);
}
}
canvas.save();
}
onTouch方法
@Override
public boolean onTouch(View v, MotionEvent event) {
mScaleDetector.onTouchEvent(event);
mGestureDetector.onTouchEvent(event);
PointF curr = new PointF(event.getX(), event.getY());
mX = event.getX() + mDistX;
mY = event.getY() + mDistY;
if (state == State.NONE || state == State.DRAG || state == State.FLING) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
drawFlag = false;
mStartX = mX;
mStartY = mY;
if (mMode == MODE_ARROW) {
mPath = new Path();
mLineDrawObject = new DrawObject(MODE_ARROW, new Pair<Path, Paint>(mPath, getLinePaint()));
drawFlag = true;
} else if (mMode == MODE_TEXT) {
drawFlag = true;
} else if (mMode == MODE_CIRCLE) {
mPath = new Path();
mCircleDrawObject = new DrawObject(MODE_CIRCLE, new Pair<Path, Paint>(mPath, getCirclePaint()));
drawFlag = true;
} else if (mMode == MODE_RECTANGLE) {
mPath = new Path();
mRectangleObject = new DrawObject(MODE_RECTANGLE, new Pair<Path, Paint>(mPath, getRectanglePaint()));
drawFlag = true;
} else if (mMode == MODE_DRAWING) {
mPath = new Path();
mDrawingDrawObject = new DrawObject(MODE_DRAWING, new Pair<Path, Paint>(mPath, getDrawPaint()));
drawFlag = true;
} else if (mMode == MODE_ERASE) {
mPath = new Path();
mEraseObject = new DrawObject(MODE_ERASE, new Pair<Path, Paint>(mPath, getErasePaint()));
drawFlag = true;
}
if (drawFlag == true) {
touch_start(mX, mY);
invalidate();
}
last.set(curr);
if (fling != null) {
fling.cancelFling();
}
setState(State.DRAG);
break;
case MotionEvent.ACTION_MOVE:
if (state == State.DRAG && drawFlag == false) {
float deltaX = curr.x - last.x;
float deltaY = curr.y - last.y;
float fixTransX = getFixDragTrans(deltaX, viewWidth,
getImageWidth());
float fixTransY = getFixDragTrans(deltaY, viewHeight,
getImageHeight());
matrix.postTranslate(fixTransX, fixTransY);
fixTrans();
last.set(curr.x, curr.y);
}
if (drawFlag == true) {
touch_move(mX, mY);
invalidate();
}
break;
case MotionEvent.ACTION_UP:
if (drawFlag == true) {
touch_up();
}
break;
case MotionEvent.ACTION_POINTER_UP:
setState(State.NONE);
break;
}
}
setImageMatrix(matrix);
//mCanvas.concat(matrix);
//
// User-defined OnTouchListener
//
if (userTouchListener != null) {
userTouchListener.onTouch(v, event);
}
//
// OnTouchImageViewListener is set: TouchImageView dragged by user.
//
if (touchImageViewListener != null) {
touchImageViewListener.onMove();
}
//
// indicate event was handled
//
return true;
}
}
您可以尝试下面的onDraw和onTouch方法。
onDraw
@Override
protected void onDraw(Canvas canvas) {
onDrawReady = true;
imageRenderedAtLeastOnce = true;
if (delayedZoomVariables != null) {
setZoom(delayedZoomVariables.scale, delayedZoomVariables.focusX, delayedZoomVariables.focusY, delayedZoomVariables.scaleType);
delayedZoomVariables = null;
}
super.onDraw(canvas);
}
onTouch
@Override
public boolean onTouch(View v, MotionEvent event) {
mScaleDetector.onTouchEvent(event);
mGestureDetector.onTouchEvent(event);
PointF curr = new PointF(event.getX(), event.getY());
if (state == State.NONE || state == State.DRAG || state == State.FLING) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
last.set(curr);
if (fling != null)
fling.cancelFling();
setState(State.DRAG);
break;
case MotionEvent.ACTION_MOVE:
if (state == State.DRAG) {
float deltaX = curr.x - last.x;
float deltaY = curr.y - last.y;
float fixTransX = getFixDragTrans(deltaX, viewWidth, getImageWidth());
float fixTransY = getFixDragTrans(deltaY, viewHeight, getImageHeight());
matrix.postTranslate(fixTransX, fixTransY);
fixTrans();
last.set(curr.x, curr.y);
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
setState(State.NONE);
break;
}
}
setImageMatrix(matrix);
//
// User-defined OnTouchListener
//
if(userTouchListener != null) {
userTouchListener.onTouch(v, event);
}
//
// OnTouchImageViewListener is set: TouchImageView dragged by user.
//
if (touchImageViewListener != null) {
touchImageViewListener.onMove();
}
//
// indicate event was handled
//
return true;
}
}
我终于找到了我所问问题的答案。这是因为触摸坐标和画布坐标之间的像素映射差异。
将此添加到onTouch方法解决了我的问题
PointF curr = new PointF();
//Add this line
curr = transformCoordTouchToBitmap(event.getX(), event.getY(), false);
mX = curr.x;
mY = curr.y;
并在代码中定义此方法。
private PointF transformCoordTouchToBitmap(float x, float y, boolean clipToBitmap) {
matrix.getValues(m);
float origW = getDrawable().getIntrinsicWidth();
float origH = getDrawable().getIntrinsicHeight();
float transX = m[Matrix.MTRANS_X];
float transY = m[Matrix.MTRANS_Y];
float finalX = ((x - transX) * origW) / getImageWidth();
float finalY = ((y - transY) * origH) / getImageHeight();
if (clipToBitmap) {
finalX = Math.min(Math.max(finalX, 0), origW);
finalY = Math.min(Math.max(finalY, 0), origH);
}
return new PointF(finalX, finalY);
}