Android getX/getY interleaves relative/absolute coordinates
Asked Answered
E

1

4

There are a lot of discussions of how MotionEvent.getX/.getY are "unreliable" (or other terms) and that we should use the Raw versions of these calls to get coordinates.

On my Nexus 7, I have discovered that .getX/.getY are reliably returning interleaved absolute and relative coordinates. In other words, say a given ACTION_MOVE event returns absolute coordinates when you call .getX and .getY. The next ACTION_MOVE event will then return relative coordinates on its .getX and .getY calls.

This cannot be accidental behavior. It also leads me to believe there must be a way to discern whether a given ACTION_MOVE will be returning absolute or relative coordinates.

Does anyone know how to check a given MotionEvent object to see if it is returning absolute vs. relative coordinates on its .getX and .getY calls?

EDIT: Per your request, here's the code. It's nothing special, just grab the coordinates and move the View object:

public boolean  onTouch(View v,MotionEvent event) {

    boolean bExitValue = true;
    float   fX;
    float   fY;
    int     iAction;

    iAction = event.getActionMasked();

    if (MotionEvent.ACTION_MOVE == iAction) {
        fX = event.getX();
        fY = event.getY();
        v.setX(fX);
        v.setY(fY);
        Log.d("",("X: " + fX + ", Y: " + fY));
    }

    else if (MotionEvent.ACTION_DOWN != iAction) {
        bExitValue = false;
    }

    return(bExitValue);

}

The Log.d call and standalone floats aren't necessary to make the code work, but they do allow you to see the interleaving of values in the LogCat window.

Eurhythmics answered 21/5, 2013 at 17:33 Comment(7)
Can you please post your code where you checked this behavior?Kathrinekathryn
Code added above, thanks. If you run this and move your finger very slowly, you can get a single coordinate pair at a time - and they will alternate between values like "X: 59.509125, Y: 75.56683" and "X: 356.14337, Y: 489.77722". Wildly different coordinate pairs, yet the odd and even sets will be consistent with each other. It's almost like having two fingers down (though this isn't how a MotionEvent would report a multitouch).Eurhythmics
What happens if you add getHistoricalX/Y to the output? Maybe relative coordinates are only returned when history data is present?Zetes
Good suggestion. I modified the Log.d output to display event.getHistorySize(). The result is one unless I'm really screaming my finger across the screen, and even then it never exceeds two. I still get the interleaved coordinate pairs even when the value is one.Eurhythmics
INTERESTING: I commented out the calls to v.setX and v.setY (so the View wouldn't move) and the interleaved coordinates stopped. I'm now getting just relative coordinates! There appears to be a connection between relocating a View and MotionEvents. Still digging....Eurhythmics
Wondering if moving a View causes a new MotionEvent to occur based on the View's "new location". It has "moved" relative to the pointer location, so I guess you could argue it should see a fresh ACTION_MOVE. I'll try to simulate that in code and see what happens.Eurhythmics
I've had to deal with this problem before. The issue is that you're repositioning your view then getting new relative coordinates, which causes the jumpy values. AFAIK, getX() and getY() always return relative coordinates. Please see my solution to this problem here: https://mcmap.net/q/1648957/-jumping-imageview-while-dragging-getx-and-gety-values-are-jumpingSerra
D
0

I have found out, that on the galaxy s 4 getY and getRawY both are wrong. But they change in an orthogonal way. So you can get the right value by the following code:

rawY = event.getRawY() - spaceOverLayout;
normalY = event.getY();
y = 0F;

float prozentPosition = ((rawY + normalY) / 2) / height;
y = (normalY * (1 - prozentPosition)) + (rawY * prozentPosition);

hopefully it will help.

Dangelo answered 4/9, 2014 at 14:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.