I have an app that uses a SimpleOnScaleGestureListener and a SimpleOnGestureListener together. Whenever I do a pinch zoom I get the expected onScale's, but when I lift off I see a weird onScroll that has a start position from the beginning of the pinch zoom and an end position from the end of the pinch zoom. My question is, can I prevent the bogus onScroll?
Here's the code:
@Override
public boolean onTouchEvent(MotionEvent event) {
// Log every event.
Log.d(TAG, Here.at() + String.format("Event: %d, Time: %d X: %f, Y: %f",
event.getAction(),
event.getEventTime(),
event.getX(),
event.getY()
));
boolean handled = mScaleDetector.onTouchEvent(event); // This appears to ALWAYS return true (online reference indicated that's what the Android code does).
handled |= mDetector.onTouchEvent(event);
handled |= super.onTouchEvent(event);
return handled;
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
// This is required. If absent, the scale gesture never starts.
Log.d(TAG, "In onScaleBegin");
mIgnoreNextDrag = true;
return true;
}
@Override
public boolean onScale(ScaleGestureDetector detector) {
Log.d(TAG, "In onScale");
mTimeScale.doScale(detector.getScaleFactor(), detector.getFocusY());
invalidate();
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector detector) {
Log.d(TAG, "In onScaleEnd");
}
}
private class GestureListener extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onScroll(MotionEvent me1, MotionEvent me2, float distanceX, float distanceY) {
Log.d(TAG, String.format("Motion Event 1: %d, Time: %d X: %f, Y: %f",
me1.getAction(),
me1.getEventTime(),
me1.getX(),
me1.getY()
));
Log.d(TAG, String.format("Event 2: %d, Time: %d X: %f, Y: %f",
me2.getAction(),
me2.getEventTime(),
me2.getX(),
me2.getY()
));
return true;
}
@Override
public boolean onSingleTapConfirmed(MotionEvent me) {
// Do tap processing.
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
// TODO: Future feature.
return true;
}
@Override
public boolean onDown(MotionEvent e) {
// This is required. If absent, the scroll gesture never starts.
return true;
}
}
Here's the LogCat:
13:06:05.885: D/my-tag(4140): In View.onTouchEvent, Event: 0, Time: 183279420 X: 171.761444, Y: 918.160767
13:06:05.895: D/my-tag(4140): In View.onTouchEvent, Event: 261, Time: 183279420 X: 171.761444, Y: 918.160767
13:06:05.895: D/my-tag(4140): In onScaleBegin
13:06:05.895: I/ScaleGestureDetector(4140): TwScaleGestureDetector
13:06:05.915: D/my-tag(4140): In View.onTouchEvent, Event: 2, Time: 183279458 X: 171.761444, Y: 908.474365
13:06:05.915: D/my-tag(4140): In onScale
13:06:06.015: D/my-tag(4140): In View.onTouchEvent, Event: 2, Time: 183279542 X: 174.964783, Y: 857.584717
13:06:06.015: D/my-tag(4140): In onScale
13:06:06.105: D/my-tag(4140): In View.onTouchEvent, Event: 2, Time: 183279641 X: 232.242096, Y: 731.365662
13:06:06.105: D/my-tag(4140): In onScale
13:06:06.215: D/my-tag(4140): In View.onTouchEvent, Event: 2, Time: 183279740 X: 313.564514, Y: 595.412964
13:06:06.215: D/my-tag(4140): In onScale
13:06:06.225: D/my-tag(4140): In View.onTouchEvent, Event: 6, Time: 183279751 X: 313.564514, Y: 595.412964
13:06:06.225: D/my-tag(4140): In onScaleEnd
13:06:06.245: D/my-tag(4140): In View.onTouchEvent, Event: 2, Time: 183279774 X: 333.316528, Y: 487.607422
13:06:06.245: D/my-tag(4140): In onScroll, me1: 0, Time: 183279420 X: 171.761444, Y: 918.160767
13:06:06.245: D/my-tag(4140): In onScroll, me2 2: 2, Time: 183279774 X: 333.316528, Y: 487.607422
13:06:06.255: D/my-tag(4140): In View.onTouchEvent, Event: 2, Time: 183279784 X: 331.539551, Y: 488.496460
13:06:06.265: D/my-tag(4140): In onScroll, me1: 0, Time: 183279420 X: 171.761444, Y: 918.160767
13:06:06.265: D/my-tag(4140): In onScroll, me2 2: 2, Time: 183279784 X: 331.539551, Y: 488.496460
13:06:06.275: D/my-tag(4140): In View.onTouchEvent, Event: 1, Time: 183279794 X: 331.539551, Y: 488.496460
You can see that the first event is the first finger down (0 = ACTION_DOWN), then the second finger down (261 = ACTION_POINTER_2_DOWN). Then we see log entry from the onScaleBegin call and a log from the scale gesture detector itself (not from my code). At this point I think I can safely assume the scale gesture has been started. This is exactly as expected.
This is followed by four move events (2 = ACTION_MOVE), each of which is immediately followed by the log entry from onScale. This is still as expected.
Then we see a pointer up event (6 = ACTION_POINTER_UP) followed by the log entry from onScaleEnd, still AOK! (Note that it's a 6 and not a 262 because I lifted my fingers in the same order that I put them down, so pointer 1 was lifted first, not pointer 2.)
Now the weird bit.
We see a move event, which gets picked up by onScroll in the SimpleOnGestureListener. The first parameter me1 has the x and y coordinates from the very first down event before the scale gesture started The second parameter me2 has coordinates that apparently reflect a position after the scale gesture had stopped.
In this example there's actually a second move event that also gets interpreted as a scroll gesture, again with the pre-scale origin point. With the above code I would variously get 1, 2 or no scroll events after pinch zooms.
(To finish off the LogCat, we a final up event (1 = ACTION_UP) for the second finger and the log goes quiet.)
So am I doing it wrong? I've tried only calling the SimpleOnGestureListener if the SimpleOnScaleGestureListener returns false from isInProgress, but no joy.
Any ideas?
Thanks in advance, and thanks to all y'all in the community for the vast amount of information I've gotten from this site over the years!