Detecting Sliding Gestures in Android

April 1, 2014

Detecting and recognizing gestures in an Android app can make intuitive shortcuts for your users to perform various tasks. Google’s GMail app uses sliding gestures such as its swipe to delete or archive inbox emails and their YouTube app uses sliding gestures to shrink and dismiss videos that are currently playing.

Detecting a sliding gesture across a View in Android seems like a simple task but it can be a little tricky. Let’s walk through how to make a simple sliding gesture detector, and get you started on the road to detecting gestures in your apps.

Let’s start with a simple activity with a single view in its layout:

package com.example.SlidingGestureExample;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;

public class MyActivity extends Activity {

 @Override
 public void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.my_activity);

 View myView = (View) findViewById(R.id.myView);
 }
}

Ultimately, what we would like to see is a nice listener that tells us when certain gestures are detected on this view, like this:

package com.example.SlidingGestureExample;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;

public class MyActivity extends Activity {

 @Override
 public void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.my_activity);

 View myView = (View) findViewById(R.id.myView);
 myView.setOnTouchListener(new OnSlidingTouchListener(this) {
 @Override
 public boolean onSlideLeft() {
 // do something
 return true;
 }

 @Override
 public boolean onSlideRight() {
 // do something
 return true;
 }

 @Override
 public boolean onSlideUp() {
 // do something
 return true;
 }

 @Override
 public boolean onSlideDown() {
 // do something
 return true;
 }
 });
 }
}

Let’s make our custom touch listener class:

package com.example.SlidingGestureExample;

import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;

public class OnSlidingTouchListener implements OnTouchListener {

 @Override
 public boolean onTouch(View v, MotionEvent event) {
 return false;
 }
}

In order to detect a somewhat complex gesture like a slide in a particular direction, we will need to make use of the Android GestureDetector class. Add a GestureDetector as a field in our custom touch listener class, create a constructor that takes in a Context as an arugment, and in onTouch(), pass the MotionEvent to the GestureDetector to handle.

public class OnSlidingTouchListener implements OnTouchListener {

 private final GestureDetector gestureDetector;

 public OnSlidingTouchListener(Context context){
 gestureDetector = new GestureDetector(context, /* we need a GestureListener here */);
 }

 public boolean onTouch(View v, MotionEvent event) {
 return gestureDetector.onTouchEvent(event);
 }
}

GestureDetector’s constructor must be provided with a GestureDetector.OnGestureListener. We’ll provide it with a private inner class implementation of SimpleOnGestureListener.

public class OnSlidingTouchListener implements OnTouchListener {

 private final GestureDetector gestureDetector;

 public OnSlidingTouchListener(Context context){
 gestureDetector = new GestureDetector(context, new GestureListener());
 }

 public boolean onTouch(View v, MotionEvent event) {
 return gestureDetector.onTouchEvent(event);
 }

 private final class GestureListener extends SimpleOnGestureListener { }
}

GestureListener, our implementation of SimpleOnGestureListener, will be used to indicate when a sliding gesture has been received. SimpleOnGestureListener has no methods to override regarding sliding gestures, but it does have one called onScoll(). We will use the typical scrolling gesture to detect a sliding gesture.

private final class GestureListener extends SimpleOnGestureListener {

 private final String TAG = GestureListener.class.getSimpleName();

 private static final int SLIDE_THRESHOLD = 100;

 @Override
 public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
 try {
 float deltaY = e2.getY() - e1.getY();
 float deltaX = e2.getX() - e1.getX();

 if (Math.abs(deltaX) > Math.abs(deltaY)) {
 if (Math.abs(deltaX) > SLIDE_THRESHOLD) {
 if (deltaX > 0) {
 // the user made a sliding right gesture
 return onSlideRight();
 } else {
 // the user made a sliding left gesture
 return onSlideLeft();
 }
 }
 } else {
 if (Math.abs(deltaY) > SLIDE_THRESHOLD) {
 if (deltaY > 0) {
 // the user made a sliding down gesture
 return onSlideDown();
 } else {
 // the user made a sliding up gesture
 return onSlideUp();
 }
 }
 }
 } catch (Exception exception) {
 Log.e(TAG, exception.getMessage());
 }

 return false;
 }
 }

What’s happening in our implementation of onScroll()? We first calculate the distance between the relative (to our View) pixel coordinates of the starting MotionEvent e1 and the coordinates of the ending MotionEvent e2. If the horizontal change, deltaX, is greater than the vertical change, deltaY, then we can assume the user made a horizontal sliding motion, and if the vertical change was greater than the horizontal change, then a vertical sliding motion was made. If the greater change is larger than a certain threshold, in this case we use 100 pixels, then, depending on whether the change was positive or negative, we have detected a right/up or left/down slide gesture, respectively.

Now let’s handle the callbacks for each of these gestures:

public class OnSlidingTouchListener implements OnTouchListener {

 private final GestureDetector gestureDetector;

 public OnSlidingTouchListener(Context context){
 gestureDetector = new GestureDetector(context, new GestureListener());
 }

 public boolean onTouch(View v, MotionEvent event) {
 return gestureDetector.onTouchEvent(event);
 }

 private final class GestureListener extends SimpleOnGestureListener {

 private final String TAG = GestureListener.class.getSimpleName();

 private static final int SLIDE_THRESHOLD = 100;

 @Override
 public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
 try {
 float deltaY = e2.getY() - e1.getY();
 float deltaX = e2.getX() - e1.getX();

 if (Math.abs(deltaX) > Math.abs(deltaY)) {
 if (Math.abs(deltaX) > SLIDE_THRESHOLD) {
 if (deltaX > 0) {
 // the user made a sliding right gesture
 return onSlideRight();
 } else {
 // the user made a sliding left gesture
 return onSlideLeft();
 }
 }
 } else {
 if (Math.abs(deltaY) > SLIDE_THRESHOLD) {
 if (deltaY > 0) {
 // the user made a sliding down gesture
 return onSlideDown();
 } else {
 // the user made a sliding up gesture
 return onSlideUp();
 }
 }
 }
 } catch (Exception exception) {
 Log.e(TAG, exception.getMessage());
 }

 return false;
 }
 }

 public boolean onSlideRight() {
 return false;
 }

 public boolean onSlideLeft() {
 return false;
 }

 public boolean onSlideUp() {
 return false;
 }

 public boolean onSlideDown() {
 return false;
 }
}

A very important piece in here is the implementation of onDown(). If this isn’t implemented to return true, then none of your gestures will appear to be recognized.

Each of these callbacks, onSlideRight(), onSlideLeft(), onSlideUp(), and onSlideDown(), are all meant to be overridden in our touch listener. Let’s go back to our activity and our View’s touch listener and add these methods:

package com.example.SlidingGestureExample;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;

public class MyActivity extends Activity {

 @Override
 public void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.my_activity);

 View myView = (View) findViewById(R.id.myView);
 myView.setOnTouchListener(new OnSlidingTouchListener(this) {
 @Override
 public boolean onSlideLeft() {
 // do something
 return true;
 }

 @Override
 public boolean onSlideRight() {
 // do something
 return true;
 }

 @Override
 public boolean onSlideUp() {
 // do something
 return true;
 }

 @Override
 public boolean onSlideDown() {
 // do something
 return true;
 }
 });
 }
}

Now myView can recognize and react to sliding gestures in each of the four directions, and handle each accordingly. In each of these, we return true to signal that the gesture was recognized and consumed, and we return false if we didn’t do anything with it.

The code from this post can be found in this Github Gist.

Joseph Kreiser
Joseph Kreiser
Software Developer

Looking for more like this?

Sign up for our monthly newsletter to receive helpful articles, case studies, and stories from our team.

What to know about the cost of custom app development
Business Process

What to know about the cost of custom app development

January 10, 2024

We hear a lot of ideas for apps at MichiganLabs. People from large enterprises and small startups, located all over the world, call us to explore their mobile and web-based application ideas, and one of the first questions they ask is: How much is this app going to cost?

Read more
Information Experience can make or break a product
Design Process

Information Experience can make or break a product

January 4, 2023

Kai discusses how writing impacts user experience, providing an overview of the types of writing that are involved in product development and how to approach it from a very high level.

Read more
The value of AR for business leaders (and when not to bother)
Business Development iOS

The value of AR for business leaders (and when not to bother)

April 24, 2024

Should you leverage AR for your new digital products? Should you build an app for Apple’s Vision Pro? Discover four common use cases for AR and when to focus your energy elsewhere.

Read more
View more articles