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

Stay in the loop with our latest content!

Select the topics you’re interested to receive our new relevant content in your inbox. Don’t worry, we won’t spam you.

Being Intentional, Flexible and People-Focused in 2021
Team

Being Intentional, Flexible and People-Focused in 2021

October 19, 2020

MichiganLabs co-founder and managing partner, Joshua Hulst, sat down with Chelsea Dubey (Guest Writer) to share his insights for a strong start to the new year and the exciting technology trends that his team is tracking for 2021.

Read more
Michigan Software Labs Ranks No. 50 on Inc. Magazine’s List of the Midwest’s Fastest-Growing Private Companies
Press Release

Michigan Software Labs Ranks No. 50 on Inc. Magazine’s List of the Midwest’s Fastest-Growing Private Companies

March 17, 2021

March 17, 2021 – Inc. magazine today revealed that Michigan Software Labs is No. 50 on its 2021 Inc. 5000 Regionals: Midwest list, the most prestigious ranking of the fastest-growing private companies in Illinois, Indiana, Iowa, Kansas, Michigan, Minnesota, Missouri, Nebraska, North Dakota, Ohio, South Dakota, and Wisconsin.

Read more
2022 Best and Brightest Winners in West Michigan
Team

2022 Best and Brightest Winners in West Michigan

May 2, 2022

The Best and Brightest Companies to Work For® competition identifies and honors organizations that display a commitment to excellence in operations and employee enrichment that lead to increased productivity and financial performance!

Read more
View more articles