How To: Identify which pointer moved in Android

Heads up: When I say pointer in this article, I mean a finger or a stylus – anything in contact with the touchscreen.

Multi-touch in Android is a bit of a strange beast, although you could argue that it’s by necessity. With ACTION_DOWN (primary pointer in contact) or ACTION_POINTER_DOWN (non-primary pointer in contact), or even the corresponding ACTION_UP or ACTION_POINTER_UP events it’s fine. But when it comes to ACTION_MOVE events – you can’t just ask which finger moved, all you’re told is that A finger moved, and you have to figure out which one for yourself as far as I can tell.

This is what I’ve come up with to figure out which pointer has actually moved – it falls behind by one ACTION_MOVE event because there doesn’t seem to be a way to ask for the current X location of a pointer by its index location (that is, there’s no getX(pointerIndex), only a getHistoricalX(pointerIndex, historyPosition)) – so this code misses the very first move event when a pointer moves – BUT – moving your finger generates a large number of move events, so I’m thinking this might not be that much of an issue.

Update: I’d forgotten you can getX(pointerIndex) and as well as getHistoricalX(pointerIndex, historyLocation) – so I’ve modified the code below to do that, which means I don’t think we miss any move events anymore because we’re now comparing current location to historical(0) rather than historical(0) to historical(1).

Anyway, here’s my code which addresses this finicky problem:

As I’ve been playing around with this it seems to match up with what I’m doing very well without issue, for example:

Alternative Solution

Keep a sparse array of whatever you’re keeping track of – for example, let’s say we’ve got the world’s simplest Circle class:

Then in your class handling the onTouchEvent() method you could have something like this (in this particular example we have a view which responds to multi-touch events):

This technique doesn’t miss any ACTION_MOVE events because it looks them up by pointerId in the SparseArray – which is potentially a nicer solution. Go with whatever works for you.

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.