在Android中,我如何正确地将像素坐标转换为画布坐标?

9
我正在使用GestureListener在Android的SurfaceView中捕获MotionEvent以进行长按操作。然后,我需要将MotionEvent的坐标转换为画布坐标,从而可以生成自定义地图坐标(不是Google Maps)。
据我所知,给定MotionEvent ee.getX()e.getY()获取像素坐标。如何将这些坐标转换为SurfaceView的画布坐标?
以下是用于监听长按操作的GestureListener代码:
/**
* Overrides touch gestures not handled by the default touch listener
*/
private class GestureListener extends GestureDetector.SimpleOnGestureListener {

  @Override
  public void onLongPress(MotionEvent e) {
     Point p = new Point();
     p.x =  (int) e.getX();
     p.y = (int) e.getY();
     //TODO translate p to canvas coordinates
  }
}

提前致谢!

编辑:这与屏幕尺寸/分辨率/深度和画布的矩形对象有关吗?


你尝试过使用 translate(float dx, float dy) 吗? - Nikola Despotoski
我已经调查过了。不幸的是,我无法在画布上绘制。我需要实际的坐标。一旦我获得了画布坐标,我计划将我的画布坐标转换为应用程序地图坐标,以便用于导航。 - Phil
真的没有其他人吗?这与屏幕大小/分辨率/深度和画布的Rect对象有关吗?难道以前没有人做过这个翻译吗? - Phil
解决了吗?我也遇到了同样的问题。 - Sibbs Gambling
http://stackoverflow.com/a/3152172/755804 - 18446744073709551615
6个回答

8

您可以尝试使用MotionEvent.getRawX()/getRawY()方法,而不是getX()/getY()方法。

// get the surfaceView's location on screen
int[] loc = new int[2];
surfaceView.getLocationOnScreen(loc);
// calculate delta
int left = e.getRawX()-loc[0];
int top = e.getRawY()-loc[1];

5

好的,你可以从显示器上获取屏幕的x,y像素,可以通过以下方式调用画布像素:

Canvas c = new Canvas();
int cx = c.getWidth();
int cy = c.getHeight();
...
Display display = getWindowManager().getDefaultDisplay(); 
int sx = display.getWidth();
int sy = display.getHeight();

然后,您可以进行数学计算,将屏幕触摸视图与视图和屏幕中给定的像素映射。

canvasCoordX = p.x*((float)cx/(float)sx);
canvasCoordY = p.y*((float)cy/(float)sy);

更多有关屏幕管理器的信息,请参见http://developer.android.com/reference/android/view/WindowManager.html。我认为它需要在活动内进行初始化才能正常工作。


谢谢你的建议。我尝试了一下,但它仍然不能正常工作。 - Phil
没有错误。它确实提供了一些翻译,但不是正确的翻译。无论我在哪里按下,它都会找到画布坐标到屏幕顶部的方式。 - Phil
我建议进行一些调试 - 可能是显示像素(px)没有正确初始化,都是0,0。打印变量,如果一切看起来还不错,就放弃这种方法吧。 :) - Noah

4

我最近在做类似的事情时遇到了这个问题,经过一些尝试和大量搜索,我最终适应了这个答案 (https://dev59.com/zm445IYBdhLWcg3wTIfm#9945896):

(e是一个MotionEvent,所以使用这段代码的最佳位置应该在onTouch或onLongPress中)

mClickCoords = new float[2];

//e is the motionevent that contains the screen touch we
//want to translate into a canvas coordinate
mClickCoords[0] = e.getX();
mClickCoords[1] = e.getY();

Matrix matrix = new Matrix();
matrix.set(getMatrix());

//this is where you apply any translations/scaling/rotation etc.
//Typically you want to apply the same adjustments that you apply
//in your onDraw().

matrix.preTranslate(mVirtualX, mVirtualY);
matrix.preScale(mScaleFactor, mScaleFactor, mPivotX, mPivotY);

// invert the matrix, creating the mapping from screen 
//coordinates to canvas coordinates
matrix.invert(matrix); 

//apply the mapping
matrix.mapPoints(mClickCoords);

//mClickCoords[0] is the canvas x coordinate and
//mClickCoords[1] is the y coordinate.

这里有一些明显的优化可以应用,但我认为这种方式更加清晰。

1
如果我理解正确,您在SurfaceView内部有一个Canvas视图。如果是这样,请尝试使用VIEW.getLeft() | getTop(),它返回视图相对于其父级的左侧|顶部位置。
float x= e.getX() - canvasView.getLeft();
float y= e.getY() - canvasView.getTop();

谢谢你的建议。我尝试了一下,但还是不行。 - Phil
当画布被缩放时该怎么办? - gi097

0
如果你正在使用滚动条,那么画布上的实际 y 坐标是:
float y = event.getY() + arg0.getScrollY();

0

在这些情况下,我所做的就是:

  1. 在您想要通过单击获取其坐标的任何View/ViewGroup上放置一个监听器
  2. 将它们本地存储
  3. 任何想要访问它们的人都应该通过帮助方法请求它们。

翻译完成...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接