In my application, I need to handle both move and click events.
A click is a sequence of one ACTION_DOWN action, several ACTION_MOVE actions and one ACTION_UP action
Taking Jonik's lead I built a slightly more fine tuned version, that doesn't register as a click if you move your finger and then return to the spot before letting go:
So here is my solution:
/**
* Max allowed duration for a "click", in milliseconds.
*/
private static final int MAX_CLICK_DURATION = 1000;
/**
* Max allowed distance to move during a "click", in DP.
*/
private static final int MAX_CLICK_DISTANCE = 15;
private long pressStartTime;
private float pressedX;
private float pressedY;
private boolean stayedWithinClickDistance;
@Override
public boolean onTouchEvent(MotionEvent e) {
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN: {
pressStartTime = System.currentTimeMillis();
pressedX = e.getX();
pressedY = e.getY();
stayedWithinClickDistance = true;
break;
}
case MotionEvent.ACTION_MOVE: {
if (stayedWithinClickDistance && distance(pressedX, pressedY, e.getX(), e.getY()) > MAX_CLICK_DISTANCE) {
stayedWithinClickDistance = false;
}
break;
}
case MotionEvent.ACTION_UP: {
long pressDuration = System.currentTimeMillis() - pressStartTime;
if (pressDuration < MAX_CLICK_DURATION && stayedWithinClickDistance) {
// Click event has occurred
}
}
}
}
private static float distance(float x1, float y1, float x2, float y2) {
float dx = x1 - x2;
float dy = y1 - y2;
float distanceInPx = (float) Math.sqrt(dx * dx + dy * dy);
return pxToDp(distanceInPx);
}
private static float pxToDp(float px) {
return px / getResources().getDisplayMetrics().density;
}