| page.title=Detecting Common Gestures |
| parent.title=Using Touch Gestures |
| parent.link=index.html |
| |
| trainingnavtop=true |
| next.title=Tracking Movement |
| next.link=movement.html |
| |
| @jd:body |
| |
| <div id="tb-wrapper"> |
| <div id="tb"> |
| |
| <!-- table of contents --> |
| <h2>This lesson teaches you to</h2> |
| <ol> |
| <li><a href="#data">Gather Data</a></li> |
| <li><a href="#detect">Detect Gestures</a></li> |
| </ol> |
| |
| <!-- other docs (NOT javadocs) --> |
| <h2>You should also read</h2> |
| |
| <ul> |
| <li><a href="http://developer.android.com/guide/topics/ui/ui-events.html">Input Events</a> API Guide |
| </li> |
| <li><a href="{@docRoot}guide/topics/sensors/sensors_overview.html">Sensors Overview</a></li> |
| <li><a href="{@docRoot}training/custom-views/making-interactive.html">Making the View Interactive</a> </li> |
| <li>Design Guide for <a href="{@docRoot}design/patterns/gestures.html">Gestures</a></li> |
| <li>Design Guide for <a href="{@docRoot}design/style/touch-feedback.html">Touch Feedback</a></li> |
| </ul> |
| |
| <h2>Try it out</h2> |
| |
| <div class="download-box"> |
| <a href="{@docRoot}shareables/training/InteractiveChart.zip" |
| class="button">Download the sample</a> |
| <p class="filename">InteractiveChart.zip</p> |
| </div> |
| |
| </div> |
| </div> |
| |
| <p>A "touch gesture" occurs when a user places one or more fingers on the touch |
| screen, and your application interprets |
| that pattern of touches as a particular gesture. There are correspondingly two |
| phases to gesture detection:</p> |
| |
| <ol> |
| <li>Gathering data about touch events.</li> |
| |
| <li>Interpreting the data to see if it meets the criteria for any of the |
| gestures your app supports. </li> |
| |
| </ol> |
| |
| <h4>Support Library Classes</h4> |
| |
| <p>The examples in this lesson use the {@link android.support.v4.view.GestureDetectorCompat} |
| and {@link android.support.v4.view.MotionEventCompat} classes. These classes are in the |
| <a href="{@docRoot}tools/support-library/index.html">Support Library</a>. You should use |
| Support Library classes where possible to provide compatibility with devices |
| running Android 1.6 and higher. Note that {@link android.support.v4.view.MotionEventCompat} is <em>not</em> a |
| replacement for the {@link android.view.MotionEvent} class. Rather, it provides static utility |
| methods to which you pass your {@link android.view.MotionEvent} object in order to receive |
| the desired action associated with that event.</p> |
| |
| <h2 id="data">Gather Data</h2> |
| |
| <p>When a user places one or more fingers on the screen, this triggers the |
| callback {@link android.view.View#onTouchEvent onTouchEvent()} |
| on the View that received the touch events. |
| For each sequence of touch events (position, pressure, size, addition of another finger, etc.) |
| that is ultimately identified as a gesture, |
| {@link android.view.View#onTouchEvent onTouchEvent()} is fired several times.</p> |
| |
| <p>The gesture starts when the user first touches the screen, continues as the system tracks |
| the position of the user's finger(s), and ends by capturing the final event of |
| the user's fingers leaving the screen. Throughout this interaction, |
| the {@link android.view.MotionEvent} delivered to {@link android.view.View#onTouchEvent onTouchEvent()} |
| provides the details of every interaction. Your app can use the data provided by the {@link android.view.MotionEvent} |
| to determine if a gesture it cares |
| about happened.</p> |
| |
| <h3>Capturing touch events for an Activity or View</h3> |
| |
| <p><p>To intercept touch events in an Activity or View, override |
| the {@link android.view.View#onTouchEvent onTouchEvent()} callback.</p> |
| |
| <p>The following snippet uses |
| {@link android.support.v4.view.MotionEventCompat#getActionMasked getActionMasked()} |
| to extract the action the user performed from the {@code event} parameter. This gives you the raw |
| data you need to determine if a gesture you care about occurred:</p> |
| |
| <pre> |
| public class MainActivity extends Activity { |
| ... |
| // This example shows an Activity, but you would use the same approach if |
| // you were subclassing a View. |
| @Override |
| public boolean onTouchEvent(MotionEvent event){ |
| |
| int action = MotionEventCompat.getActionMasked(event); |
| |
| switch(action) { |
| case (MotionEvent.ACTION_DOWN) : |
| Log.d(DEBUG_TAG,"Action was DOWN"); |
| return true; |
| case (MotionEvent.ACTION_MOVE) : |
| Log.d(DEBUG_TAG,"Action was MOVE"); |
| return true; |
| case (MotionEvent.ACTION_UP) : |
| Log.d(DEBUG_TAG,"Action was UP"); |
| return true; |
| case (MotionEvent.ACTION_CANCEL) : |
| Log.d(DEBUG_TAG,"Action was CANCEL"); |
| return true; |
| case (MotionEvent.ACTION_OUTSIDE) : |
| Log.d(DEBUG_TAG,"Movement occurred outside bounds " + |
| "of current screen element"); |
| return true; |
| default : |
| return super.onTouchEvent(event); |
| } |
| }</pre> |
| |
| <p>You can then do your own processing on these events to determine if a |
| gesture occurred. This is the kind of processing you would have to do for a |
| custom gesture. However, if your app uses |
| common gestures such as double tap, long press, fling, and so on, you can |
| take advantage of the {@link |
| android.view.GestureDetector} class. {@link |
| android.view.GestureDetector} makes it easy for you to detect common |
| gestures without processing the individual touch events yourself. This is |
| discussed below in <a href="#detect">Detect Gestures</a>.</p> |
| |
| <h3>Capturing touch events for a single view</h3> |
| |
| <p>As an alternative to {@link android.view.View#onTouchEvent onTouchEvent()}, |
| you can attach an {@link android.view.View.OnTouchListener} object to any {@link |
| android.view.View} object using the {@link android.view.View#setOnTouchListener |
| setOnTouchListener()} method. This makes it possible to to listen for touch |
| events without subclassing an existing {@link android.view.View}. For |
| example:</p> |
| |
| <pre>View myView = findViewById(R.id.my_view); |
| myView.setOnTouchListener(new OnTouchListener() { |
| public boolean onTouch(View v, MotionEvent event) { |
| // ... Respond to touch events |
| return true; |
| } |
| });</pre> |
| |
| <p>Beware of creating a listener that returns {@code false} for the |
| {@link android.view.MotionEvent#ACTION_DOWN} event. If you do this, the listener will |
| not be called for the subsequent {@link android.view.MotionEvent#ACTION_MOVE} |
| and {@link android.view.MotionEvent#ACTION_UP} string of events. This is because |
| {@link android.view.MotionEvent#ACTION_DOWN} is the starting point for all touch events.</p> |
| |
| <p>If you are creating a custom View, you can override |
| {@link android.view.View#onTouchEvent onTouchEvent()}, |
| as described above.</p> |
| |
| <h2 id="detect">Detect Gestures</h2> |
| |
| <p>Android provides the {@link android.view.GestureDetector} class for detecting |
| common gestures. Some of the gestures it supports include {@link |
| android.view.GestureDetector.OnGestureListener#onDown onDown()}, {@link |
| android.view.GestureDetector.OnGestureListener#onLongPress onLongPress()}, |
| {@link android.view.GestureDetector.OnGestureListener#onFling onFling()}, and so |
| on. You can use {@link android.view.GestureDetector} in conjunction with the |
| {@link android.view.View#onTouchEvent onTouchEvent()} |
| method described above.</p> |
| |
| |
| <h3>Detecting All Supported Gestures</h3> |
| |
| <p>When you instantiate a {@link android.support.v4.view.GestureDetectorCompat} |
| object, one of the parameters it takes is a class that implements the |
| {@link android.view.GestureDetector.OnGestureListener} interface. |
| {@link android.view.GestureDetector.OnGestureListener} notifies users when |
| a particular touch event has occurred. To make it possible for your |
| {@link android.view.GestureDetector} object to receive events, you override |
| the View or Activity's {@link android.view.View#onTouchEvent onTouchEvent()} method, |
| and pass along all observed events to the detector instance.</p> |
| |
| |
| <p>In the following snippet, a return value of {@code true} from the individual |
| {@code on<em><TouchEvent></em>} methods indicates that you |
| have handled the touch event. A return value of {@code false} passes events down |
| through the view stack until the touch has been successfully handled.</p> |
| |
| <p>Run the following snippet to get a feel for how actions are triggered when |
| you interact with the touch screen, and what the contents of the {@link |
| android.view.MotionEvent} are for each touch event. You will realize how much |
| data is being generated for even simple interactions.</p> |
| |
| <pre>public class MainActivity extends Activity implements |
| GestureDetector.OnGestureListener, |
| GestureDetector.OnDoubleTapListener{ |
| |
| private static final String DEBUG_TAG = "Gestures"; |
| private GestureDetectorCompat mDetector; |
| |
| // Called when the activity is first created. |
| @Override |
| public void onCreate(Bundle savedInstanceState) { |
| super.onCreate(savedInstanceState); |
| setContentView(R.layout.activity_main); |
| // Instantiate the gesture detector with the |
| // application context and an implementation of |
| // GestureDetector.OnGestureListener |
| mDetector = new GestureDetectorCompat(this,this); |
| // Set the gesture detector as the double tap |
| // listener. |
| mDetector.setOnDoubleTapListener(this); |
| } |
| |
| @Override |
| public boolean onTouchEvent(MotionEvent event){ |
| this.mDetector.onTouchEvent(event); |
| // Be sure to call the superclass implementation |
| return super.onTouchEvent(event); |
| } |
| |
| @Override |
| public boolean onDown(MotionEvent event) { |
| Log.d(DEBUG_TAG,"onDown: " + event.toString()); |
| return true; |
| } |
| |
| @Override |
| public boolean onFling(MotionEvent event1, MotionEvent event2, |
| float velocityX, float velocityY) { |
| Log.d(DEBUG_TAG, "onFling: " + event1.toString()+event2.toString()); |
| return true; |
| } |
| |
| @Override |
| public void onLongPress(MotionEvent event) { |
| Log.d(DEBUG_TAG, "onLongPress: " + event.toString()); |
| } |
| |
| @Override |
| public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, |
| float distanceY) { |
| Log.d(DEBUG_TAG, "onScroll: " + e1.toString()+e2.toString()); |
| return true; |
| } |
| |
| @Override |
| public void onShowPress(MotionEvent event) { |
| Log.d(DEBUG_TAG, "onShowPress: " + event.toString()); |
| } |
| |
| @Override |
| public boolean onSingleTapUp(MotionEvent event) { |
| Log.d(DEBUG_TAG, "onSingleTapUp: " + event.toString()); |
| return true; |
| } |
| |
| @Override |
| public boolean onDoubleTap(MotionEvent event) { |
| Log.d(DEBUG_TAG, "onDoubleTap: " + event.toString()); |
| return true; |
| } |
| |
| @Override |
| public boolean onDoubleTapEvent(MotionEvent event) { |
| Log.d(DEBUG_TAG, "onDoubleTapEvent: " + event.toString()); |
| return true; |
| } |
| |
| @Override |
| public boolean onSingleTapConfirmed(MotionEvent event) { |
| Log.d(DEBUG_TAG, "onSingleTapConfirmed: " + event.toString()); |
| return true; |
| } |
| }</pre> |
| |
| <h3>Detecting a Subset of Supported Gestures</h3> |
| |
| <p>If you only want to process a few gestures, you can extend {@link |
| android.view.GestureDetector.SimpleOnGestureListener} instead of implementing |
| the {@link android.view.GestureDetector.OnGestureListener} interface. </p> |
| <p> |
| {@link |
| android.view.GestureDetector.SimpleOnGestureListener} provides an implementation |
| for all of the {@code on<em><TouchEvent></em>} methods by returning {@code false} |
| for all of them. Thus you can override only the methods you care about. |
| For |
| example, the snippet below creates a class that extends {@link |
| android.view.GestureDetector.SimpleOnGestureListener} and overrides {@link |
| android.view.GestureDetector.OnGestureListener#onFling onFling()} and {@link |
| android.view.GestureDetector.OnGestureListener#onDown onDown()}.</p> |
| |
| <p>Whether or not you use {@link android.view.GestureDetector.OnGestureListener}, |
| it's best practice to implement an |
| {@link android.view.GestureDetector.OnGestureListener#onDown onDown()} |
| method that returns {@code true}. This is because all gestures begin with an |
| {@link android.view.GestureDetector.OnGestureListener#onDown onDown()} message. If you return |
| {@code false} from {@link android.view.GestureDetector.OnGestureListener#onDown onDown()}, |
| as {@link android.view.GestureDetector.SimpleOnGestureListener} does by default, |
| the system assumes that you want to ignore the rest of the gesture, and the other methods of |
| {@link android.view.GestureDetector.OnGestureListener} never get called. |
| This has the potential to cause unexpected problems in your app. |
| The only time you should return {@code false} from |
| {@link android.view.GestureDetector.OnGestureListener#onDown onDown()} |
| is if you truly want to ignore an entire gesture. </p> |
| |
| <pre>public class MainActivity extends Activity { |
| |
| private GestureDetectorCompat mDetector; |
| |
| @Override |
| public void onCreate(Bundle savedInstanceState) { |
| super.onCreate(savedInstanceState); |
| setContentView(R.layout.activity_main); |
| mDetector = new GestureDetectorCompat(this, new MyGestureListener()); |
| } |
| |
| @Override |
| public boolean onTouchEvent(MotionEvent event){ |
| this.mDetector.onTouchEvent(event); |
| return super.onTouchEvent(event); |
| } |
| |
| class MyGestureListener extends GestureDetector.SimpleOnGestureListener { |
| private static final String DEBUG_TAG = "Gestures"; |
| |
| @Override |
| public boolean onDown(MotionEvent event) { |
| Log.d(DEBUG_TAG,"onDown: " + event.toString()); |
| return true; |
| } |
| |
| @Override |
| public boolean onFling(MotionEvent event1, MotionEvent event2, |
| float velocityX, float velocityY) { |
| Log.d(DEBUG_TAG, "onFling: " + event1.toString()+event2.toString()); |
| return true; |
| } |
| } |
| } |
| </pre> |
| |
| |