Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use ScaleGestureDetector with GestureDetector?

In my Android app I have an ImageView where I'd like the user to be able to fling it left/right/up/down to change the image (static maps) to the adjacent one. But in addition, I'd like pinch-zoom abilities and a map itself.

I can get either flinging OR pinch-zooming to work, but not together. I'm using GestureDetector (with a SimpleOnGestureListener) for the flinging. And I'm using ScaleGestureDetector (from Making Sense of Multitouch) for the scaling.

The difficulty is to determine which gesture listener to invoke upon a touch action. This is less a coding issue, but logic issue. Upon a single finger touch action, is it a fling or scale? Even when a pinch-zoom is used, the initial MotionEvent is ACTION_DOWN. I've been trying to use the image size (intrinsic or scaled?) as a decision point. But the initial scaling operation (when image size is intrinsic and I want to zoom on it) with ACTION_DOWN seems to escape me.

Has anyone tackled this successfully previously?

like image 822
mraviator Avatar asked Mar 09 '13 10:03

mraviator


3 Answers

You can pass the events on to both gesture detectors.

Check http://developer.android.com/training/gestures/scale.html under "More complex scaling example":

public boolean onTouchEvent(MotionEvent event) {
    boolean retVal = mScaleGestureDetector.onTouchEvent(event);
    retVal = mGestureDetector.onTouchEvent(event) || retVal;
    return retVal || super.onTouchEvent(event);
}

Of course given the bug Ratatat is referencing, super.onTouchEvent will never be called in the above example, which may or may not be fine, depending on your use case.

like image 51
aij Avatar answered Nov 01 '22 17:11

aij


The idea of Ratatat's answer is OK but we should still pass events to the gestureDetector even if we don't want to scroll, or it will be messed up.

I ended up with something like this:

scaleDetector = new ScaleGestureDetector( ... );

gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        if (scaleDetector.isInProgress()) {
            // don't allow scrolling while scaling
            return false;
        }

        // handle scrolling

        return true;
    }
}

And then onTouchEvent's implementation should be like in aij's answer:

boolean result = scaleDetector.onTouchEvent(event);
result = gestureDetector.onTouchEvent(event) || result;
return result || super.onTouchEvent(event);
like image 23
yonix Avatar answered Nov 01 '22 15:11

yonix


Finally found the answer on a link: http://code.google.com/p/android/issues/detail?id=42591

@Override
public boolean onTouchEvent(MotionEvent event) {
    boolean result = mScaleGestureDetector.onTouchEvent(event);

    // result is always true here, so I need another way to check for a detected scaling gesture
    boolean isScaling = result = mScaleGestureDetector.isInProgress();
    if (!isScaling) {
        // if no scaling is performed check for other gestures (fling, long tab, etc.)
        result = mCommonGestureDetector.onTouchEvent(event);
    }

    // some irrelevant checks...

    return result ? result : super.onTouchEvent(event);
}
like image 2
Ratatat Richie Avatar answered Nov 01 '22 15:11

Ratatat Richie