3

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.

ADM
  • 20,406
  • 11
  • 52
  • 83
DIRTY DAVE
  • 2,523
  • 2
  • 20
  • 83

1 Answers1

3

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
    }
}));
beigirad
  • 4,986
  • 2
  • 29
  • 52
  • Why does the ```view.getContext()``` always equal to ```null```? I passed it with my view thats already created in the onCreate method – DIRTY DAVE Feb 19 '21 at 17:44
  • ```sceneView = findViewById(R.id.sceneview);``` ```sceneView.setOnTouchListener(new Gesture(sceneView``` https://i.imgur.com/qkDTBdq.png – DIRTY DAVE Feb 19 '21 at 17:47
  • @DIRTYDAVE Where's onCreate? I wrote it for a view. It doesn't matter in fragment or activity. – beigirad Feb 19 '21 at 17:49
  • All of them returns to the MainActivity as context but for view getting context from their parent is better. try my code – beigirad Feb 19 '21 at 17:52
  • I think your view is null and you're looking for the view with an unassociated id. check view id in XML and in java code. – beigirad Feb 19 '21 at 17:55