• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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&#64;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>&lt;TouchEvent&gt;</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    &#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
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>&lt;TouchEvent&gt;</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    &#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