Home | History | Annotate | Download | only in gestures
      1 page.title=Detecting Common Gestures
      2 parent.title=Using Touch Gestures
      3 parent.link=index.html
      4 
      5 trainingnavtop=true
      6 next.title=Tracking Movement
      7 next.link=movement.html
      8 
      9 @jd:body
     10 
     11 <div id="tb-wrapper">
     12 <div id="tb">
     13 
     14 <!-- table of contents -->
     15 <h2>This lesson teaches you to</h2>
     16 <ol>
     17   <li><a href="#data">Gather Data</a></li>
     18   <li><a href="#detect">Detect Gestures</a></li>
     19 </ol>
     20 
     21 <!-- other docs (NOT javadocs) -->
     22 <h2>You should also read</h2>
     23 
     24 <ul>
     25    <li><a href="http://developer.android.com/guide/topics/ui/ui-events.html">Input Events</a> API Guide
     26     </li>
     27     <li><a href="{@docRoot}guide/topics/sensors/sensors_overview.html">Sensors Overview</a></li>
     28     <li><a href="{@docRoot}training/custom-views/making-interactive.html">Making the View Interactive</a> </li>
     29     <li>Design Guide for <a href="{@docRoot}design/patterns/gestures.html">Gestures</a></li>
     30     <li>Design Guide for <a href="{@docRoot}design/style/touch-feedback.html">Touch Feedback</a></li>
     31 </ul>
     32 
     33 <h2>Try it out</h2>
     34 
     35 <div class="download-box">
     36   <a href="{@docRoot}shareables/training/InteractiveChart.zip"
     37 class="button">Download the sample</a>
     38  <p class="filename">InteractiveChart.zip</p>
     39 </div>
     40 
     41 </div>
     42 </div>
     43 
     44 <p>A "touch gesture" occurs when a user places one or more fingers on the touch
     45 screen, and your application interprets
     46 that pattern of touches as a particular gesture. There are correspondingly two
     47 phases to gesture detection:</p>
     48 
     49 <ol>
     50   <li>Gathering data about touch events.</li>
     51   
     52   <li>Interpreting the data to see if it meets the criteria for any of the
     53 gestures your app supports. </li> 
     54 
     55 </ol>
     56 
     57 <h4>Support Library Classes</h4>
     58 
     59 <p>The examples in this lesson use the {@link android.support.v4.view.GestureDetectorCompat}
     60 and {@link android.support.v4.view.MotionEventCompat} classes. These classes are in the 
     61 <a href="{@docRoot}tools/extras/support-library.html">Support Library</a>. You should use
     62 Support Library classes where possible to provide compatibility with devices 
     63 running Android 1.6 and higher. Note that {@link android.support.v4.view.MotionEventCompat} is <em>not</em> a 
     64 replacement for the {@link android.view.MotionEvent} class. Rather, it provides static utility 
     65 methods to which you pass your {@link android.view.MotionEvent} object in order to receive 
     66 the desired action associated with that event.</p>
     67 
     68 <h2 id="data">Gather Data</h2>
     69 
     70 <p>When a user places one or more fingers on the screen, this  triggers the
     71 callback {@link android.view.View#onTouchEvent onTouchEvent()} 
     72 on the View that received the touch events.
     73 For each sequence of touch events (position, pressure, size, addition of another finger, etc.) 
     74 that is ultimately identified as a gesture,
     75 {@link android.view.View#onTouchEvent onTouchEvent()} is fired several times.</p>
     76 
     77 <p>The gesture starts when the user first touches the screen, continues as the system tracks
     78 the position of the user's finger(s), and ends by capturing the final event of
     79 the user's fingers leaving the screen. Throughout this interaction, 
     80 the {@link android.view.MotionEvent} delivered to {@link android.view.View#onTouchEvent onTouchEvent()} 
     81 provides the details of every interaction. Your app can use the data provided by the {@link android.view.MotionEvent} 
     82 to determine if a gesture it cares
     83 about happened.</p>
     84 
     85 <h3>Capturing touch events for an Activity or View</h3>
     86 
     87 <p><p>To intercept touch events in an Activity or View, override 
     88 the {@link android.view.View#onTouchEvent onTouchEvent()} callback.</p>
     89 
     90 <p>The following snippet uses 
     91 {@link android.support.v4.view.MotionEventCompat#getActionMasked getActionMasked()}
     92 to extract the action the user performed from the {@code event} parameter. This gives you the raw 
     93 data you need to determine if a gesture you care about occurred:</p>
     94 
     95 <pre>
     96 public class MainActivity extends Activity {
     97 ...
     98 // This example shows an Activity, but you would use the same approach if
     99 // you were subclassing a View.
    100 &#64;Override
    101 public boolean onTouchEvent(MotionEvent event){ 
    102         
    103     int action = MotionEventCompat.getActionMasked(event);
    104         
    105     switch(action) {
    106         case (MotionEvent.ACTION_DOWN) :
    107             Log.d(DEBUG_TAG,"Action was DOWN");
    108             return true;
    109         case (MotionEvent.ACTION_MOVE) :
    110             Log.d(DEBUG_TAG,"Action was MOVE");
    111             return true;
    112         case (MotionEvent.ACTION_UP) :
    113             Log.d(DEBUG_TAG,"Action was UP");
    114             return true;
    115         case (MotionEvent.ACTION_CANCEL) :
    116             Log.d(DEBUG_TAG,"Action was CANCEL");
    117             return true;
    118         case (MotionEvent.ACTION_OUTSIDE) :
    119             Log.d(DEBUG_TAG,"Movement occurred outside bounds " +
    120                     "of current screen element");
    121             return true;      
    122         default : 
    123             return super.onTouchEvent(event);
    124     }      
    125 }</pre>
    126 
    127 <p>You can then do your own processing on these events to determine if a
    128 gesture occurred. This is the kind of processing you would have to do for a
    129 custom gesture. However, if your app uses
    130 common gestures such as double tap, long press, fling, and so on, you can
    131 take advantage of the {@link
    132 android.view.GestureDetector} class. {@link
    133 android.view.GestureDetector} makes it easy for you to detect common
    134 gestures without processing the individual touch events yourself. This is
    135 discussed below in <a href="#detect">Detect Gestures</a>.</p>
    136 
    137 <h3>Capturing touch events for a single view</h3>
    138 
    139 <p>As an alternative to {@link android.view.View#onTouchEvent onTouchEvent()},
    140 you can attach an {@link android.view.View.OnTouchListener} object to any {@link
    141 android.view.View} object using the {@link android.view.View#setOnTouchListener
    142 setOnTouchListener()} method. This makes it possible to to listen for touch
    143 events without subclassing an existing {@link android.view.View}. For
    144 example:</p>
    145 
    146 <pre>View myView = findViewById(R.id.my_view); 
    147 myView.setOnTouchListener(new OnTouchListener() {
    148     public boolean onTouch(View v, MotionEvent event) {
    149         // ... Respond to touch events       
    150         return true;
    151     }
    152 });</pre>
    153 
    154 <p>Beware of creating a listener that returns {@code false} for the 
    155 {@link android.view.MotionEvent#ACTION_DOWN} event. If you do this, the listener will 
    156 not be called for the subsequent {@link android.view.MotionEvent#ACTION_MOVE} 
    157 and {@link android.view.MotionEvent#ACTION_UP} string of events. This is because
    158 {@link android.view.MotionEvent#ACTION_DOWN} is the starting point for all touch events.</p>
    159 
    160 <p>If you are creating a custom View, you can override 
    161 {@link android.view.View#onTouchEvent onTouchEvent()}, 
    162 as described above.</p>
    163 
    164 <h2 id="detect">Detect Gestures</h2>
    165 
    166 <p>Android provides the {@link android.view.GestureDetector} class for detecting
    167 common gestures. Some of the gestures it supports include {@link
    168 android.view.GestureDetector.OnGestureListener#onDown onDown()}, {@link
    169 android.view.GestureDetector.OnGestureListener#onLongPress onLongPress()},
    170 {@link android.view.GestureDetector.OnGestureListener#onFling onFling()}, and so
    171 on. You can use {@link android.view.GestureDetector} in conjunction with the 
    172 {@link android.view.View#onTouchEvent onTouchEvent()}
    173 method described above.</p>
    174 
    175 
    176 <h3>Detecting All Supported Gestures</h3>
    177 
    178 <p>When you instantiate a {@link android.support.v4.view.GestureDetectorCompat} 
    179 object, one of the parameters it takes is a class that implements the 
    180 {@link android.view.GestureDetector.OnGestureListener} interface.  
    181 {@link android.view.GestureDetector.OnGestureListener} notifies users when 
    182 a particular touch event has occurred. To make it possible for your 
    183 {@link android.view.GestureDetector} object to receive events, you override 
    184 the View or Activity's {@link android.view.View#onTouchEvent onTouchEvent()} method, 
    185 and pass along all observed events to the detector instance.</p>
    186 
    187 
    188 <p>In the following snippet, a return value of {@code true} from the individual 
    189 {@code on<em>&lt;TouchEvent&gt;</em>} methods indicates that you
    190 have handled the touch event. A return value of {@code false} passes events down
    191 through the view stack until the touch has been successfully handled.</p>
    192 
    193 <p>Run the following snippet to get a feel for how actions are triggered when
    194 you interact with the touch screen, and what the contents of the {@link
    195 android.view.MotionEvent} are for each touch event. You will realize how much
    196 data is being generated for even simple interactions.</p>
    197 
    198 <pre>public class MainActivity extends Activity implements 
    199         GestureDetector.OnGestureListener,
    200         GestureDetector.OnDoubleTapListener{
    201     
    202     private static final String DEBUG_TAG = "Gestures";
    203     private GestureDetectorCompat mDetector; 
    204 
    205     // Called when the activity is first created. 
    206     &#64;Override
    207     public void onCreate(Bundle savedInstanceState) {
    208         super.onCreate(savedInstanceState);
    209         setContentView(R.layout.activity_main);
    210         // Instantiate the gesture detector with the
    211         // application context and an implementation of
    212         // GestureDetector.OnGestureListener
    213         mDetector = new GestureDetectorCompat(this,this);
    214         // Set the gesture detector as the double tap
    215         // listener.
    216         mDetector.setOnDoubleTapListener(this);
    217     }
    218 
    219     &#64;Override 
    220     public boolean onTouchEvent(MotionEvent event){ 
    221         this.mDetector.onTouchEvent(event);
    222         // Be sure to call the superclass implementation
    223         return super.onTouchEvent(event);
    224     }
    225 
    226     &#64;Override
    227     public boolean onDown(MotionEvent event) { 
    228         Log.d(DEBUG_TAG,"onDown: " + event.toString()); 
    229         return true;
    230     }
    231 
    232     &#64;Override
    233     public boolean onFling(MotionEvent event1, MotionEvent event2, 
    234             float velocityX, float velocityY) {
    235         Log.d(DEBUG_TAG, "onFling: " + event1.toString()+event2.toString());
    236         return true;
    237     }
    238 
    239     &#64;Override
    240     public void onLongPress(MotionEvent event) {
    241         Log.d(DEBUG_TAG, "onLongPress: " + event.toString()); 
    242     }
    243 
    244     &#64;Override
    245     public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
    246             float distanceY) {
    247         Log.d(DEBUG_TAG, "onScroll: " + e1.toString()+e2.toString());
    248         return true;
    249     }
    250 
    251     &#64;Override
    252     public void onShowPress(MotionEvent event) {
    253         Log.d(DEBUG_TAG, "onShowPress: " + event.toString());
    254     }
    255 
    256     &#64;Override
    257     public boolean onSingleTapUp(MotionEvent event) {
    258         Log.d(DEBUG_TAG, "onSingleTapUp: " + event.toString());
    259         return true;
    260     }
    261 
    262     &#64;Override
    263     public boolean onDoubleTap(MotionEvent event) {
    264         Log.d(DEBUG_TAG, "onDoubleTap: " + event.toString());
    265         return true;
    266     }
    267 
    268     &#64;Override
    269     public boolean onDoubleTapEvent(MotionEvent event) {
    270         Log.d(DEBUG_TAG, "onDoubleTapEvent: " + event.toString());
    271         return true;
    272     }
    273 
    274     &#64;Override
    275     public boolean onSingleTapConfirmed(MotionEvent event) {
    276         Log.d(DEBUG_TAG, "onSingleTapConfirmed: " + event.toString());
    277         return true;
    278     }
    279 }</pre>
    280 
    281 <h3>Detecting a Subset of Supported Gestures</h3>
    282 
    283 <p>If you only want to process a few gestures, you can extend {@link
    284 android.view.GestureDetector.SimpleOnGestureListener} instead of implementing
    285 the {@link android.view.GestureDetector.OnGestureListener} interface. </p>
    286 <p>
    287 {@link
    288 android.view.GestureDetector.SimpleOnGestureListener} provides an implementation
    289 for all of the {@code on<em>&lt;TouchEvent&gt;</em>} methods by returning {@code false}
    290 for all of them. Thus you can override only the methods you care about.
    291 For
    292 example, the snippet below creates a class that extends {@link
    293 android.view.GestureDetector.SimpleOnGestureListener} and overrides {@link
    294 android.view.GestureDetector.OnGestureListener#onFling onFling()} and {@link
    295 android.view.GestureDetector.OnGestureListener#onDown onDown()}.</p>
    296 
    297 <p>Whether or not you use {@link android.view.GestureDetector.OnGestureListener}, 
    298 it's best practice to implement an 
    299 {@link android.view.GestureDetector.OnGestureListener#onDown onDown()} 
    300 method that returns {@code true}. This is because all gestures begin with an 
    301 {@link android.view.GestureDetector.OnGestureListener#onDown onDown()} message. If you return 
    302 {@code false} from {@link android.view.GestureDetector.OnGestureListener#onDown onDown()}, 
    303 as {@link android.view.GestureDetector.SimpleOnGestureListener} does by default, 
    304 the system assumes that you want to ignore the rest of the gesture, and the other methods of 
    305 {@link android.view.GestureDetector.OnGestureListener} never get called. 
    306 This has the potential to cause unexpected problems in your app. 
    307 The only time you should return {@code false} from 
    308 {@link android.view.GestureDetector.OnGestureListener#onDown onDown()} 
    309 is if you truly want to ignore an entire gesture. </p>
    310 
    311 <pre>public class MainActivity extends Activity { 
    312     
    313     private GestureDetectorCompat mDetector; 
    314 
    315     &#64;Override
    316     public void onCreate(Bundle savedInstanceState) {
    317         super.onCreate(savedInstanceState);
    318         setContentView(R.layout.activity_main);
    319         mDetector = new GestureDetectorCompat(this, new MyGestureListener());
    320     }
    321 
    322     &#64;Override 
    323     public boolean onTouchEvent(MotionEvent event){ 
    324         this.mDetector.onTouchEvent(event);
    325         return super.onTouchEvent(event);
    326     }
    327     
    328     class MyGestureListener extends GestureDetector.SimpleOnGestureListener {
    329         private static final String DEBUG_TAG = "Gestures"; 
    330         
    331         &#64;Override
    332         public boolean onDown(MotionEvent event) { 
    333             Log.d(DEBUG_TAG,"onDown: " + event.toString()); 
    334             return true;
    335         }
    336 
    337         &#64;Override
    338         public boolean onFling(MotionEvent event1, MotionEvent event2, 
    339                 float velocityX, float velocityY) {
    340             Log.d(DEBUG_TAG, "onFling: " + event1.toString()+event2.toString());
    341             return true;
    342         }
    343     }
    344 }
    345 </pre>
    346 
    347 
    348