简体   繁体   中英

How do I correctly translate pixel coordinates to canvas coordinates in Android?

I am capturing a MotionEvent for a long click in an Android SurfaceView using a GestureListener . I then need to translate the coordinates of the MotionEvent to canvas coordinates, from which I can generate custom map coordinates (not Google Maps).

From what I have read, I take that given MotionEvent e , e.getX() and e.getY() get pixel coordinates. How can I convert these coordinates to the SurfaceView 's canvas coordinates?

Here is my GestureListener for listening for long clicks:

/**
* 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
  }
}

Thanks in advance!

Edit: Does this have to do with screen size/resolution/depth and the canvas' Rect object?

You might try using the MotionEvent.getRawX()/getRawY() methods instead of the 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];

Well, you have the screen px from the display in x,y, and you can call the canvas px via:

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

Then, you can do the math to map the screen touch view , with the given px in both the view and the screen.

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

See http://developer.android.com/reference/android/view/WindowManager.html for more info on the screen manager. I think it needs to be initialized inside an activity to work.

I recently came upon this problem while doing something very similiar and after some trial and error and lots of googling I ended up adapting this answer ( https://stackoverflow.com/a/9945896/1131180 ) :

(e is a MotionEvent, so the best place to use this code would be in onTouch or 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.

There are some obvious optimizations that can be applied here but I think it is more clear this way.

If i understand correctly you have a canvas View inside surfaceview. If so try VIEW.getLeft() | getTop() VIEW.getLeft() | getTop() that returns the left | top position of the view relative to it's parent.

float x= e.getX() - canvasView.getLeft();
float y= e.getY() - canvasView.getTop();

如果你使用滚动,那么画布上的实际y是

float y = event.getY() + arg0.getScrollY();

What I do in these situations is just:

  1. put a listener on whatever View/ViewGroup whose coordinates you wanna get by click
  2. Make it store them locally
  3. Whoever wants to access them should just request them via helper method.

And translation is done...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM