Search code examples
androidgesture

Android: several gesture detectors on the same view


I have a TextView wrapped with ScrollView. The thing I need to do is to detect scale and common gestures (like tap, double tab and others) on my TextView. Also, I want some gestures to handle with standard handlers (scroll, for example). I just can't get the basics, I don't know what do I code for this. I made two detectors (ScaleGestureDetector and GestureDetector) and listeners for them. Also, I set onTouchListener for my TextView like this:

tw.setOnTouchListener(new OnTouchListener() {
    public boolean onTouch(View view, MotionEvent motionEvent) {
        if (!gestureDetector.onTouchEvent(motionEvent)) {
            scaleGestureDetector.onTouchEvent(motionEvent);
        };
        return true;
    }
});

No gestures are being detected. Every example which I googled operates with one detector. Could somebody help me out with the concept, how do I detect scale (or pinch zoom), double tap, single tap etc. on the same view?


Solution

  • One solution is to call onTouchEvent for both of your Detectors:

    tw.setOnTouchListener(new OnTouchListener() {
        public boolean onTouch(View view, MotionEvent motionEvent) {
            gestureDetector.onTouchEvent(motionEvent);
            scaleGestureDetector.onTouchEvent(motionEvent);
            return true;
        }
    });
    

    This may, however, lead to undesirable behavior as both Detectors may simultaneously trigger; for example, one gesture may be identified as both a scale gesture and a scroll gesture.

    To solve this, you can introduce a new variable scaleOngoing to keep track of whether or not a scale event is ongoing:

    scaleGestureDetector = new ScaleGestureDetector(context, new ScaleGestureDetector.OnScaleGestureListener() {
        public void onScaleEnd(ScaleGestureDetector detector) {
            scaleOngoing = false;
        }
        public boolean onScaleBegin(ScaleGestureDetector detector) {
            scaleOngoing = true;
            return true;
        }
        public boolean onScale(ScaleGestureDetector detector) {
            // do scaling here
            return false;
        }
    });
    

    Then have your GestureDetector's listener check whether a scale gesture is occurring:

    mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            if(!scaleOngoing) {
                // do scrolling here
             }
             return true;
        }
    });