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.

Mark Schultheiss
  • 32,614
  • 12
  • 69
  • 100
AndroidNewbie
  • 515
  • 5
  • 17
  • Can you please post your code where you checked this behavior? – thiagolr May 21 '13 at 18:06
  • 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). – AndroidNewbie May 21 '13 at 19:29
  • What happens if you add [getHistoricalX/Y](https://developer.android.com/reference/android/view/MotionEvent.html#getHistoricalX%28int,%20int%29) to the output? Maybe relative coordinates are only returned when history data is present? – j.holetzeck May 21 '13 at 19:40
  • 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. – AndroidNewbie May 21 '13 at 20:37
  • 1
    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.... – AndroidNewbie May 21 '13 at 20:44
  • 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. – AndroidNewbie May 21 '13 at 20:59
  • 1
    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: http://stackoverflow.com/a/17549458/2448305 – Ben Kane Nov 01 '13 at 18:56

1 Answers1

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.

MaInStReAm
  • 57
  • 2