Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add a gesture detector to a view in Android

I was struggling with adding a gesture detector to a subview in my project. Do I override the parent's onTouchEvent or the child's onTouchEvent? Do I make an OnTouchListener and add the gesture detector there? The documentation shows an example for how to add a gesture detector to the activity itself but it is not clear how to add it to a view. The same process could be used if subclassing a view (example here), but I want to add the gesture without subclassing anything.

This is the closest other question I could find but it is specific to a fling gesture on an ImageView, not to the general case of any View. Also there is some disagreement in those answers about when to return true or false.

To help myself understand how it works, I made a stand alone project. My answer is below.

like image 848
Suragch Avatar asked Jul 12 '17 10:07

Suragch


People also ask

What is a gesture detector?

android.view.GestureDetector. Detects various gestures and events using the supplied MotionEvent s. The OnGestureListener callback will notify users when a particular motion event has occurred. This class should only be used with MotionEvent s reported via touch (don't use for trackball events).

How do I use onTouchEvent on Android?

After the Math. abs() calls, you're essentially testing if their finger is farther down the screen than it is across the screen. Store the initial down coordinates as member variables and set them during ACTION_DOWN . You declared two floats (touchX and touchY) inside the onTouchEvent method.


2 Answers

This example shows how to add a gesture detector to a view. The layout is just a single View inside of an Activity. You can use the same method to add a gesture detector to any type of view.

enter image description here

We will add the gesture detector to the green View.

MainActivity.java

The basic idea is to add an OnTouchListener to the view. Normally we would get all the raw touch data here (like ACTION_DOWN, ACTION_MOVE, ACTION_UP, etc.), but instead of handling it ourselves, we will forward it on to a gesture detector to do the interpretation of the touch data.

We are using a SimpleOnGestureListener. The nice thing about this gesture detector is that we only need to override the gestures that we need. In the example here I included a lot of them. You can remove the ones you don't need. (You should always return true in onDown(), though. Returning true means that we are handling the event. Returning false will make the system stop giving us any more touch events.)

public class MainActivity extends AppCompatActivity {      private GestureDetector mDetector;      @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_main);          // this is the view we will add the gesture detector to         View myView = findViewById(R.id.my_view);          // get the gesture detector         mDetector = new GestureDetector(this, new MyGestureListener());          // Add a touch listener to the view         // The touch listener passes all its events on to the gesture detector         myView.setOnTouchListener(touchListener);     }      // This touch listener passes everything on to the gesture detector.     // That saves us the trouble of interpreting the raw touch events      // ourselves.     View.OnTouchListener touchListener = new View.OnTouchListener() {         @Override         public boolean onTouch(View v, MotionEvent event) {             // pass the events to the gesture detector             // a return value of true means the detector is handling it             // a return value of false means the detector didn't              // recognize the event             return mDetector.onTouchEvent(event);          }     };      // In the SimpleOnGestureListener subclass you should override      // onDown and any other gesture that you want to detect.     class MyGestureListener extends GestureDetector.SimpleOnGestureListener {          @Override         public boolean onDown(MotionEvent event) {             Log.d("TAG","onDown: ");              // don't return false here or else none of the other              // gestures will work             return true;         }          @Override         public boolean onSingleTapConfirmed(MotionEvent e) {             Log.i("TAG", "onSingleTapConfirmed: ");             return true;         }          @Override         public void onLongPress(MotionEvent e) {             Log.i("TAG", "onLongPress: ");         }          @Override         public boolean onDoubleTap(MotionEvent e) {             Log.i("TAG", "onDoubleTap: ");             return true;         }          @Override         public boolean onScroll(MotionEvent e1, MotionEvent e2,                                  float distanceX, float distanceY) {             Log.i("TAG", "onScroll: ");             return true;         }          @Override         public boolean onFling(MotionEvent event1, MotionEvent event2,                                float velocityX, float velocityY) {             Log.d("TAG", "onFling: ");             return true;         }     } } 

It is a quick setup to run this project, so I recommend you try it out. Notice how and when the log events occur.

like image 71
Suragch Avatar answered Sep 19 '22 16:09

Suragch


short version in kotlin to detect double tap only for a view:

val gestureDetector = GestureDetector(activity, object : GestureDetector.SimpleOnGestureListener() {     override fun onDoubleTap(e: MotionEvent?): Boolean {         Log.d("myApp", "double tap")         return true     } }) myView.setOnTouchListener { _, event -> gestureDetector.onTouchEvent(event) } 

and don't forget to make myView clickable

like image 33
Palejandro Avatar answered Sep 20 '22 16:09

Palejandro