1page.title=Detecting Common Gestures 2parent.title=Using Touch Gestures 3parent.link=index.html 4 5trainingnavtop=true 6next.title=Tracking Movement 7next.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" 37class="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 45screen, and your application interprets 46that pattern of touches as a particular gesture. There are correspondingly two 47phases 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 53gestures 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} 60and {@link android.support.v4.view.MotionEventCompat} classes. These classes are in the 61<a href="{@docRoot}tools/support-library/index.html">Support Library</a>. You should use 62Support Library classes where possible to provide compatibility with devices 63running Android 1.6 and higher. Note that {@link android.support.v4.view.MotionEventCompat} is <em>not</em> a 64replacement for the {@link android.view.MotionEvent} class. Rather, it provides static utility 65methods to which you pass your {@link android.view.MotionEvent} object in order to receive 66the 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 71callback {@link android.view.View#onTouchEvent onTouchEvent()} 72on the View that received the touch events. 73For each sequence of touch events (position, pressure, size, addition of another finger, etc.) 74that 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 78the position of the user's finger(s), and ends by capturing the final event of 79the user's fingers leaving the screen. Throughout this interaction, 80the {@link android.view.MotionEvent} delivered to {@link android.view.View#onTouchEvent onTouchEvent()} 81provides the details of every interaction. Your app can use the data provided by the {@link android.view.MotionEvent} 82to determine if a gesture it cares 83about 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 88the {@link android.view.View#onTouchEvent onTouchEvent()} callback.</p> 89 90<p>The following snippet uses 91{@link android.support.v4.view.MotionEventCompat#getActionMasked getActionMasked()} 92to extract the action the user performed from the {@code event} parameter. This gives you the raw 93data you need to determine if a gesture you care about occurred:</p> 94 95<pre> 96public 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@Override 101public 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 128gesture occurred. This is the kind of processing you would have to do for a 129custom gesture. However, if your app uses 130common gestures such as double tap, long press, fling, and so on, you can 131take advantage of the {@link 132android.view.GestureDetector} class. {@link 133android.view.GestureDetector} makes it easy for you to detect common 134gestures without processing the individual touch events yourself. This is 135discussed 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()}, 140you can attach an {@link android.view.View.OnTouchListener} object to any {@link 141android.view.View} object using the {@link android.view.View#setOnTouchListener 142setOnTouchListener()} method. This makes it possible to to listen for touch 143events without subclassing an existing {@link android.view.View}. For 144example:</p> 145 146<pre>View myView = findViewById(R.id.my_view); 147myView.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 156not be called for the subsequent {@link android.view.MotionEvent#ACTION_MOVE} 157and {@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()}, 162as described above.</p> 163 164<h2 id="detect">Detect Gestures</h2> 165 166<p>Android provides the {@link android.view.GestureDetector} class for detecting 167common gestures. Some of the gestures it supports include {@link 168android.view.GestureDetector.OnGestureListener#onDown onDown()}, {@link 169android.view.GestureDetector.OnGestureListener#onLongPress onLongPress()}, 170{@link android.view.GestureDetector.OnGestureListener#onFling onFling()}, and so 171on. You can use {@link android.view.GestureDetector} in conjunction with the 172{@link android.view.View#onTouchEvent onTouchEvent()} 173method 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} 179object, 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 182a particular touch event has occurred. To make it possible for your 183{@link android.view.GestureDetector} object to receive events, you override 184the View or Activity's {@link android.view.View#onTouchEvent onTouchEvent()} method, 185and 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><TouchEvent></em></code> methods indicates that you 190have handled the touch event. A return value of {@code false} passes events down 191through 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 194you interact with the touch screen, and what the contents of the {@link 195android.view.MotionEvent} are for each touch event. You will realize how much 196data 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 @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 @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 @Override 227 public boolean onDown(MotionEvent event) { 228 Log.d(DEBUG_TAG,"onDown: " + event.toString()); 229 return true; 230 } 231 232 @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 @Override 240 public void onLongPress(MotionEvent event) { 241 Log.d(DEBUG_TAG, "onLongPress: " + event.toString()); 242 } 243 244 @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 @Override 252 public void onShowPress(MotionEvent event) { 253 Log.d(DEBUG_TAG, "onShowPress: " + event.toString()); 254 } 255 256 @Override 257 public boolean onSingleTapUp(MotionEvent event) { 258 Log.d(DEBUG_TAG, "onSingleTapUp: " + event.toString()); 259 return true; 260 } 261 262 @Override 263 public boolean onDoubleTap(MotionEvent event) { 264 Log.d(DEBUG_TAG, "onDoubleTap: " + event.toString()); 265 return true; 266 } 267 268 @Override 269 public boolean onDoubleTapEvent(MotionEvent event) { 270 Log.d(DEBUG_TAG, "onDoubleTapEvent: " + event.toString()); 271 return true; 272 } 273 274 @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 284android.view.GestureDetector.SimpleOnGestureListener} instead of implementing 285the {@link android.view.GestureDetector.OnGestureListener} interface. </p> 286<p> 287{@link 288android.view.GestureDetector.SimpleOnGestureListener} provides an implementation 289for all of the <code>on<em><TouchEvent></em></code> methods by returning {@code false} 290for all of them. Thus you can override only the methods you care about. 291For 292example, the snippet below creates a class that extends {@link 293android.view.GestureDetector.SimpleOnGestureListener} and overrides {@link 294android.view.GestureDetector.OnGestureListener#onFling onFling()} and {@link 295android.view.GestureDetector.OnGestureListener#onDown onDown()}.</p> 296 297<p>Whether or not you use {@link android.view.GestureDetector.OnGestureListener}, 298it's best practice to implement an 299{@link android.view.GestureDetector.OnGestureListener#onDown onDown()} 300method 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()}, 303as {@link android.view.GestureDetector.SimpleOnGestureListener} does by default, 304the 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. 306This has the potential to cause unexpected problems in your app. 307The only time you should return {@code false} from 308{@link android.view.GestureDetector.OnGestureListener#onDown onDown()} 309is 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 @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 @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 @Override 332 public boolean onDown(MotionEvent event) { 333 Log.d(DEBUG_TAG,"onDown: " + event.toString()); 334 return true; 335 } 336 337 @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