androidandroid-animationandroid-gesture

Adding multiple gestures on a view, not working


I'm trying to add multiple gestures onto a view. I have successfully got them to work separately, but when I combine, only one ends up working, what am I doing incorrectly?

The first gesture I'm adding is a Scale Gesture:

public class MyScaleGestures implements View.OnTouchListener, ScaleGestureDetector.OnScaleGestureListener {
        private View view;
        private ScaleGestureDetector gestureScale;
        private float scaleFactor = 1;
        private boolean inScale = false;

        public MyScaleGestures (Context c){ gestureScale = new ScaleGestureDetector(c, this); }

        @Override
        public boolean onTouch(View view, MotionEvent event) {
            this.view = view;
            gestureScale.onTouchEvent(event);
            return true;
        }

        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            scaleFactor *= detector.getScaleFactor();
            Log.d(TAG, "onScale: " + scaleFactor);
            view.setScaleX(scaleFactor);
            view.setScaleY(scaleFactor);
            return true;
        }

        @Override
        public boolean onScaleBegin(ScaleGestureDetector detector) {
            return true;
        }

        @Override
        public void onScaleEnd(ScaleGestureDetector detector) { inScale = false; }
    }

and my second Gesture is a SimpleOnGestureListener:

 private class FlingGestureDetector extends GestureDetector.SimpleOnGestureListener {
            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
                

                return true;
            }

            @Override
            public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
                

                return true;
            }
        }

Combining both into one class:

public class OnSwipeTouchListener implements View.OnTouchListener, ScaleGestureDetector.OnScaleGestureListener {

        private final GestureDetector gestureDetector;
        private ScaleGestureDetector gestureScale;

        private OnSwipeTouchListener(Context context) {
            gestureDetector = new GestureDetector(context, new FlingGestureDetector());
            gestureScale = new ScaleGestureDetector(context, this);
        }

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

        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            Log.d(TAG, "onScale: " + detector.getScaleFactor());
            return false;
        }

and using it:

sceneView.setOnTouchListener(new OnSwipeTouchListener(this));

After combining them, only one the first gesture ends up working (gestureDetector). How can I get both to listen onto the view?

When combining them, the onScale method is never called when performing the pinch action in gestureScale. But it works seperately when I don't include the other gesture.


Solution

  • You need to wrap all your gestures on one OnTouchListener class and implement your logic.

    In the below example, I missed all arguments. and you should provide all of them by your requirement.

    import android.view.GestureDetector;
    import android.view.MotionEvent;
    import android.view.ScaleGestureDetector;
    import android.view.View;
    
    class MyGesture implements View.OnTouchListener {
        private View view;
        private MyDetector myDetector;
    
        private ScaleGestureDetector scaleDetector;
        private GestureDetector gestureDetector;
    
        public MyGesture(View view, MyDetector myDetector) {
            this.view = view;
            this.myDetector = myDetector;
    
            initialGestures();
        }
    
        private void initialGestures() {
            scaleDetector = new ScaleGestureDetector(
                    view.getContext(),
                    new ScaleGestureDetector.SimpleOnScaleGestureListener() {
                        @Override
                        public boolean onScale(ScaleGestureDetector detector) {
                            myDetector.onScale();
                            return true;
                        }
                    });
    
            gestureDetector = new GestureDetector(
                    view.getContext(),
                    new GestureDetector.SimpleOnGestureListener() {
                        @Override
                        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
                            myDetector.onFling();
                            return false;
                        }
                    });
        }
    
    
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            gestureDetector.onTouchEvent(event);
            scaleDetector.onTouchEvent(event);
            return true;
        }
    
    
        interface MyDetector {
            void onScale();
    
            void onFling();
        }
    }
    

    and use it:

    myView.setOnTouchListener(new MyGesture(myView, new MyGesture.MyDetector() {
        @Override
        public void onScale() {
            // do sth
        }
    
        @Override
        public void onFling() {
            // do sth
        }
    }));