2

有人可以帮我一些关于我正在尝试构建的 mapview 的事情。我有一个渲染器,它采用画布并在其中绘制位图。我创建了一个视图并在构造函数中创建:

bitmap = Bitmap.createBitmap(windowWidth, windowHeight, Bitmap.Config.ARGB_8888);
canvas = new Canvas(bitmap);
drawable = new BitmapDrawable(bitmap);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
this.Render();

在 onDraw 方法中我有这个:

super.onDraw(canvas);
canvas.save();
canvas.translate(mPosX, mPosY);
canvas.scale(mScaleFactor, mScaleFactor);
drawable.draw(canvas);
canvas.restore();

现在我想实现平移和缩放(目前我在没有保存瓷砖的情况下工作)这是我的 onTouch:

mScaleDetector.onTouchEvent(ev);

final int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {

case MotionEvent.ACTION_DOWN: {
    this.hasPanned = false;
    final float x = ev.getX();
    final float y = ev.getY();

    mLastTouchX = x;
    mLastTouchY = y;
    mActivePointerId = ev.getPointerId(0);
    break;
}

case MotionEvent.ACTION_MOVE: {
    final int pointerIndex = ev.findPointerIndex(mActivePointerId);
    final float x = ev.getX(pointerIndex);
    final float y = ev.getY(pointerIndex);

    if (!mScaleDetector.isInProgress()) {
        final float dx = x - mLastTouchX;
        final float dy = y - mLastTouchY;

        mPosX += dx;
        mPosY += dy;

        invalidate();
    }

    mLastTouchX = x;
    mLastTouchY = y;

    break;
}

case MotionEvent.ACTION_UP: {
    mActivePointerId = INVALID_POINTER_ID;
    if (this.mDownTouchX != this.mLastTouchX && this.mDownTouchY != mLastTouchY)
        this.hasPanned = true;
    break;
}

case MotionEvent.ACTION_CANCEL: {
    mActivePointerId = INVALID_POINTER_ID;
    break;
}

case MotionEvent.ACTION_POINTER_UP: {
    final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) 
            >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
    final int pointerId = ev.getPointerId(pointerIndex);
    if (pointerId == mActivePointerId) {
        final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
        mLastTouchX = ev.getX(newPointerIndex);
        mLastTouchY = ev.getY(newPointerIndex);
        mActivePointerId = ev.getPointerId(newPointerIndex);
    }
    break;
}
}
return true;

这是我想要的和我遇到的问题:

  1. 当我平移时,我想以像素为单位计算距离,这样我就可以告诉我的渲染器何时再次渲染图像。这是如何实现的?通过记住 ACTION_DOWN 上的坐标并与 ACTION_UP 中的新坐标进行比较?
  2. 当平移完成(并且图像被重新渲染)时,我想将画布(图像)设置回其原始位置。目前它保持窗格(因为canvas.translate?)
  3. 如何处理缩放手势?使用此代码用手指进行缩小时,图像被“拖动”到左上角...

我是 android ( 和 java ) 的新手,所以非常感谢任何帮助。

4

2 回答 2

2

如果您的缩放代码缩放 Canvas 但没有正确移动它,我怀疑您调用了错误的 Canvas.scale() 方法。您使用的方法似乎是-

scale(float sx, float sy)

我认为你需要使用 -

scale(float sx, float sy, float px, float py)

sx & sy 显然是 x & y 比例因子(我通常将它们设置为相同的值)。px & py 是缩放操作的中心点,例如 MotionEvent.ACTION_DOWN 和 MotionEvent.ACTION_POINTER_DOWN 事件坐标之间的中点。

在我的 MotionEvent.ACTION_POINTER_DOWN 处理程序中,我调用 -

midPoint(mid, event);

中定义为 -

private PointF mid = new PointF();

midPoint 函数是 -

private void midPoint(PointF point, MotionEvent event) 
{
   float x = event.getX(0) + event.getX(1);
   float y = event.getY(0) + event.getY(1);
   point.set(x / 2, y / 2);
}

所以在我的 MotionEvent.ACTION_MOVE 处理程序中,我会调用 -

Canvas.scale(sx, sy, mid.x, mid.y);
于 2011-05-31T19:13:33.967 回答
1

1)是的,在 ACTION_DOWN 只是做

PontF downAt = new PointF(event.getX(), event.getY());

并在 ACTION_UP 中计算像素之间的差异。

2) MapView 与 ImageView 的工作方式不同。对于 MapView,您将使用

mapView.getController().animateTo(GeoPoint);

但我认为您真的想从 ImageView 子类化并覆盖 onDraw(Canvas canvas) 方法以直接访问 Canvas。然后使用矩阵来处理平移和缩放,例如

imageView.setScaleType(ImageView.ScaleType.MATRIX);
Matrix imageMatrix = new Matrix();
imageMatrix.postTranslate(xMove, yMove);
imageMatrix.postScale(scaleX, scaleY, midX, midY);
imageView.setImageMatrix(imageMatrix);

3) 要处理 ZOOM 手势,您需要处理 ACTION_POINTER_DOWN、ACTION_MOVE 和 ACTION_POINTER_UP 事件。这里有一个非常好的教程 - How to use Multi-touch in Android

缩放 imageView 时要小心,任何后续绘图都需要 X、Y 坐标也缩放,请使用 Matrix mapPoints(Pts) 方法来执行此操作。

于 2011-05-27T20:26:28.527 回答