Android Gesture Detectors

Filed Under: Android

In this tutorial, we’ll be discussing and implementing Gestures in our Android Application. Gestures can be a little tricky at first. But once mastered, they are really handy.

Android Gesture Detectors

The Gesture Detector class is used to detect touch events from the user. The GestureListener supplies the MotionEvent performed by the user.

You can use the GestureDetector.SimpleOnGestureListener class to listen to a subset of gestures.

Those gestures include the following:

  • onDown
  • onScroll
  • onSingleTap
  • onDoubleTap
  • onLongPress
  • onFling
Gestures play the MVP role in Animations. They always enhance the user experience.

Let’s look at each of the methods available in the SimpleOnGestureListener class:

  • onDown(MotionEvent e): Notifies when a tap occurs with the down MotionEvent that triggered it.
  • onDoubleTap(MotionEvent e): Notifies when a double-tap occurs.
  • onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY): Notifies of a fast swipe event when it occurs with the initial on down MotionEvent and the matching up MotionEvent. We can set the speed threshold of the fling/swipe
  • onLongPress(MotionEvent e): Notifies when a long press occurs with the initial on down MotionEvent that trigged it.
  • onSingleTapConfirmed(MotionEvent e): Notifies when a single-tap occurs.
  • onShowPress(MotionEvent e): This occurs when a user has performed a down MotionEvent and not performed a move or up yet.

Now in the next section, we’ll be developing a simple Android Application with a Button on which we can perform the above-discussed Gestures.

Project Structure

Android Gesture Detector Project Structure

Android Gesture Detector Project Structure

Code

The code for the activity_main.xml layout is given below:


<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/button"
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:text="DO YOUR GESTURES ON ME"
        android:textColor="@android:color/white"
        android:background="@color/colorPrimary"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

The code for the MainActivity.java class is given below:


package com.journaldev.androidgesturedetector;

import android.content.Context;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button button = findViewById(R.id.button);
        button.setOnTouchListener(new OnSwipeTouchListener(this) {
            public void onSwipeTop() {
                Toast.makeText(getApplicationContext(), "Swiped top", Toast.LENGTH_SHORT).show();
            }

            public void onSwipeRight() {
                Toast.makeText(getApplicationContext(), "Swiped right", Toast.LENGTH_SHORT).show();
            }

            public void onSwipeLeft() {
                Toast.makeText(getApplicationContext(), "Swiped left", Toast.LENGTH_SHORT).show();
            }

            public void onSwipeBottom() {
                Toast.makeText(getApplicationContext(), "Swiped bottom", Toast.LENGTH_SHORT).show();
            }

        });
    }

    class OnSwipeTouchListener implements View.OnTouchListener {

        private final GestureDetector gestureDetector;

        public OnSwipeTouchListener(Context ctx) {
            gestureDetector = new GestureDetector(ctx, new GestureListener());
        }

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

        private final class GestureListener extends GestureDetector.SimpleOnGestureListener {

            private static final int SWIPE_THRESHOLD = 300;
            private static final int SWIPE_VELOCITY_THRESHOLD = 300;

            @Override
            public boolean onDown(MotionEvent e) {
                return true;
            }

            @Override
            public boolean onSingleTapConfirmed(MotionEvent e) {
                Log.i("TAG", "onSingleTapConfirmed:");
                Toast.makeText(getApplicationContext(), "Single Tap Detected", Toast.LENGTH_SHORT).show();
                return true;
            }

            @Override
            public void onLongPress(MotionEvent e) {
                Log.i("TAG", "onLongPress:");
                Toast.makeText(getApplicationContext(), "Long Press Detected", Toast.LENGTH_SHORT).show();
            }

            @Override
            public boolean onDoubleTap(MotionEvent e) {
                Toast.makeText(getApplicationContext(), "Double Tap Detected", Toast.LENGTH_SHORT).show();
                return true;
            }

            @Override
            public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
                boolean result = false;
                try {
                    float diffY = e2.getY() - e1.getY();
                    float diffX = e2.getX() - e1.getX();
                    if (Math.abs(diffX) > Math.abs(diffY)) {
                        if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
                            if (diffX > 0) {
                                onSwipeRight();
                            } else {
                                onSwipeLeft();
                            }
                            result = true;
                        }
                    } else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
                        if (diffY > 0) {
                            onSwipeBottom();
                        } else {
                            onSwipeTop();
                        }
                        result = true;
                    }
                } catch (Exception exception) {
                    exception.printStackTrace();
                }
                return result;
            }
        }

        public void onSwipeRight() {
        }

        public void onSwipeLeft() {
        }

        public void onSwipeTop() {
        }

        public void onSwipeBottom() {
        }
    }
}

In the above code, returning false instead of true in the methods, would cause the gesture to not work. Especially, the onDown one can cause all gestures to not work, if false.

The onFling method, there are two things: Swipe Threshold and Velocity threshold.

Swipe threshold indicates the difference between the initial and final position of touch in any of the four directions.

Velocity threshold indicates how quickly was it swiped to be termed as a Gesture.

The output of the application in action is given below. It doesn’t show the finger movements due to video constraints. Hence, we’ll encourage you to try it yourself from the sample code attached at the end of this tutorial.

Android Gesture Detector Output

Android Gesture Detector Output

That brings an end to this tutorial. You can download the project from the link below:

Comments

  1. jj says:

    This is the best GestureDetector demo I found. My compliments!

Leave a Reply

Your email address will not be published. Required fields are marked *

close
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages