Reputation: 20764
I am using a SimpleOnGestureListener to detect the onSingleTapUp event an a View.
The view has a scale factor of 5, therefore 1 screen pixel corresponds to 5 pixels on my view:
view.setScaleX(5);
view.setScaleY(5);
The problem I am facing is that the Tap event is not detected accurately. I looked in the source code of SimpleOnGestureListener
, the relevant parts are:
SingleTapUp()
listener is called if the touch points haven't moved over a certain thresholdI think the reason why the Tap is not detected reliably is that the distance calculation for the touch points relies on the scaled local coordinates of the view (e.getX()
and e.getY()
) instead of the raw coordinates (e.getRawX()
and e.getRawY()
).
Due to the scale factor tiny movements of the finger on screen will cause large changes in e.getX()
and e.getY()
.
Is my interpretation of the code correct? If so, how can I work around this problem?
For now my workaround is to intercept all events on a View
that has no scale factor and then do the dispatching of the MotionEvents
myself to the views that have the scale factor.
It works well, still I'd be interested if my analysis of the android code is correct or not.
I am using android 4.4
Upvotes: 3
Views: 345
Reputation: 6356
IMHO, your analysis of code is correct!
Just some additional information which was found exploring source code:
mTouchSlopSquare
and initialized here (stored as square of original value, just for optimizations)GestureDetector
's constructor (which should be, because second one is obsolete) then this value equals to com.android.internal.R.dimen.config_viewConfigurationTouchSlop
according to this lineAs workaround I suggest you to access to private member mTouchSlopSquare
of GestureDetector
and add scale factor this distance calculation.
See my code below:
// Utility method
public static boolean fixGestureDetectorScale(GestureDetector detector, float scale) {
try {
Field f = GestureDetector.class.getDeclaredField("mTouchSlopSquare");
f.setAccessible(true);
int touchSlopSquare = (int) f.get(detector);
float touchSlop = (float) Math.sqrt(touchSlopSquare);
//normalize touchSlop
touchSlop /= scale;
touchSlopSquare = Math.round(touchSlop * touchSlop);
f.set(detector, touchSlopSquare);
} catch (NoSuchFieldException e) {
e.printStackTrace();
return false;
} catch (IllegalAccessException e) {
e.printStackTrace();
return false;
}
return true;
}
// usage
fixGestureDetectorScale(mGestureDetector, scale);
view.setScaleX(scale);
view.setScaleY(scale);
I've checked and it works for me.
Upvotes: 1