This lesson teaches you to
You should also read
- Input Events API Guide
- Sensors Overview
- Making the View Interactive
- Design Guide for Gestures
- Design Guide for Touch Feedback
Try it out
InteractiveChart.zip
A multi-touch gesture is when multiple pointers (fingers) touch the screen at the same time. This lesson describes how to detect gestures that involve multiple pointers.
Track Multiple Pointers
When multiple pointers touch the screen at the same time, the system generates the following touch events:
ACTION_DOWN
—For the first pointer that touches the screen. This starts the gesture. The pointer data for this pointer is always at index 0 in theMotionEvent
.ACTION_POINTER_DOWN
—For extra pointers that enter the screen beyond the first. The pointer data for this pointer is at the index returned bygetActionIndex()
.ACTION_MOVE
—A change has happened during a press gesture.ACTION_POINTER_UP
—Sent when a non-primary pointer goes up.ACTION_UP
—Sent when the last pointer leaves the screen.
You keep track of individual pointers within a MotionEvent
via each pointer's index and ID:
- Index: A
MotionEvent
effectively stores information about each pointer in an array. The index of a pointer is its position within this array. Most of theMotionEvent
methods you use to interact with pointers take the pointer index as a parameter, not the pointer ID. - ID: Each pointer also has an ID mapping that stays persistent across touch events to allow tracking an individual pointer across the entire gesture.
The order in which individual pointers appear within a motion event is
undefined. Thus the index of a pointer can change from one event to the
next, but the pointer ID of a pointer is guaranteed to remain constant as long
as the pointer remains active. Use the getPointerId()
method to obtain a
pointer's ID to track the pointer across all subsequent motion events in a
gesture. Then for successive motion events, use the findPointerIndex()
method to obtain
the pointer index for a given pointer ID in that motion event. For example:
private int mActivePointerId; public boolean onTouchEvent(MotionEvent event) { .... // Get the pointer ID mActivePointerId = event.getPointerId(0); // ... Many touch events later... // Use the pointer ID to find the index of the active pointer // and fetch its position int pointerIndex = event.findPointerIndex(mActivePointerId); // Get the pointer's current position float x = event.getX(pointerIndex); float y = event.getY(pointerIndex); }
Get a MotionEvent's Action
You should always use the method
getActionMasked()
(or better yet, the compatability version
MotionEventCompat.getActionMasked()
) to retrieve
the action of a
MotionEvent
. Unlike the older getAction()
method, getActionMasked()
is designed to work with
multiple pointers. It returns the masked action
being performed, without including the pointer index bits. You can then use
getActionIndex()
to return the index of
the pointer associated with the action. This is illustrated in the snippet below.
Note: This example uses the
MotionEventCompat
class. This class is in the
Support Library. You should use
MotionEventCompat
to provide the best support for a wide range of
platforms. Note that MotionEventCompat
is not a
replacement for the MotionEvent
class. Rather, it provides static utility
methods to which you pass your MotionEvent
object in order to receive
the desired action associated with that event.
int action = MotionEventCompat.getActionMasked(event); // Get the index of the pointer associated with the action. int index = MotionEventCompat.getActionIndex(event); int xPos = -1; int yPos = -1; Log.d(DEBUG_TAG,"The action is " + actionToString(action)); if (event.getPointerCount() > 1) { Log.d(DEBUG_TAG,"Multitouch event"); // The coordinates of the current screen contact, relative to // the responding View or Activity. xPos = (int)MotionEventCompat.getX(event, index); yPos = (int)MotionEventCompat.getY(event, index); } else { // Single touch event Log.d(DEBUG_TAG,"Single touch event"); xPos = (int)MotionEventCompat.getX(event, index); yPos = (int)MotionEventCompat.getY(event, index); } ... // Given an action int, returns a string description public static String actionToString(int action) { switch (action) { case MotionEvent.ACTION_DOWN: return "Down"; case MotionEvent.ACTION_MOVE: return "Move"; case MotionEvent.ACTION_POINTER_DOWN: return "Pointer Down"; case MotionEvent.ACTION_UP: return "Up"; case MotionEvent.ACTION_POINTER_UP: return "Pointer Up"; case MotionEvent.ACTION_OUTSIDE: return "Outside"; case MotionEvent.ACTION_CANCEL: return "Cancel"; } return ""; }
For more discussion of multi-touch and some examples, see the lesson Dragging and Scaling.