Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get Touch Coordinates Relative To A View (ScreenToClient Equivalent?)

Tags:

java

android

I have an image I am displaying to a user in my android application.

I want to be able to tell where they 'touch' the image.

I can easily get the screen coordinates by implementing an OnTouchListener

 private OnTouchListener image_Listener = new OnTouchListener(){
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if(event.getAction() == MotionEvent.ACTION_UP) {
            float x = event.getX();
            float y = event.getY();
            return true;
        }
        return false;
    }
};

However, these are absolute coordinates. What I really need is a function to convert this into coordinates relative to a View..

I have done a bit of digging, but I can't seem to turn up anything, aside from me trying to implement a ScreenToClient method myself..

Does anyone know of a good solution to this, or am I just going to have to roll my own?

It seems like the kind of method that would be available - that's why I'm asking.

Thank you all for your time.

EDIT: I'm not so sure that the coordinates aren't already relative to the view. I could have swore reading that coordinates were absolute, but after some tinkering - I have things working as I expected.. Sorry for the noise guys.

like image 402
syllogism Avatar asked Dec 09 '11 21:12

syllogism


2 Answers

Just to answer, the touches are relative to view in a way. Yes, they are raw screen coordinates of the touch. However, since you register the touch event to the view itself, it will only fire if the user actually touches the view. That means, even though the screen coordinates are raw screen coordinates, they are within the bounds of the view itself.

If you want to get the x/y coordinates of the touched view in relation to only itself, then you can subract the left coordinate with the screen coordinate and the top coordinate from the y coordinate like so:

private OnTouchListener image_Listener = new OnTouchListener(){
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if(event.getAction() == MotionEvent.ACTION_UP) {
            float screenX = event.getX();
            float screenY = event.getY();
            float viewX = screenX - v.getLeft();
            float viewY = screenY - v.getTop();
            return true;
        }
        return false;
    }
};

With that, if the user touched 40 x-pixels down the screen, but the left margin was set to 10, then viewX would be 30. If you moved the view down 40 x-pixels and the user touched the same spot in the view, it would still be 30.

It gets slightly more complicated if you included padding as padding within a View still counts as a View even though it doesn't display anything.

EDIT:

I should point out that what Pierre said is true. If you touch a view, then it will continue to receive touch events until the finger is lifted even if you drag your finger outside the view bounds. This means, ACTION_UP can receive touch coordinates for your view that are not within the bounds.

like image 165
DeeV Avatar answered Sep 20 '22 03:09

DeeV


I have just had the same problem, and trying the DeeV solution I always got 0 from both getLeft() and getTop() methods. As changing the layout wasn't an option (because I think that getTop/Left are relative only to the view's parent) I had to figure out how to get the absolute position of the view.

Here is a similar approach using getLocationOnScreen(location):

protected Point getRelativePosition(View v, MotionEvent event) {
    int[] location = new int[2];
    v.getLocationOnScreen(location);
    float screenX = event.getRawX();
    float screenY = event.getRawY();
    float viewX = screenX - location[0];
    float viewY = screenY - location[1];
    return new Point((int) viewX, (int) viewY);
}
like image 23
DNax Avatar answered Sep 22 '22 03:09

DNax