Trying to implement long press by borrowing code from GestureDetector I arrived at a minimal sample which does not receive message in GestureHandler when onTouchEvent() returns true. When returning false, message does get delivered, but event processing ends and the long press does not get cancelled.
Is there a way to make this code work with onTouchEvent() returning true?
public class OverlayView extends View {
private static final int LONG_PRESS = 1;
private Handler handler;
private static final String TAG = OverlayView.class.getName();
private class GestureHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case LONG_PRESS:
dispatchLongPress();
break;
default:
throw new RuntimeException("Unknown message " + msg);
}
}
}
public OverlayView(Context context, AttributeSet attrs) {
super(context, attrs);
handler = new GestureHandler();
}
private void dispatchLongPress() {
Toast.makeText(getContext(), "Long Press", Toast.LENGTH_SHORT).show();
}
@Override
public boolean onTouchEvent(MotionEvent e) {
Log.d(TAG, e.toString());
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN:
handler.removeMessages(LONG_PRESS);
handler.sendEmptyMessageAtTime(LONG_PRESS, e.getDownTime() + 1000);
break;
case MotionEvent.ACTION_MOVE:
handler.removeMessages(LONG_PRESS);
break;
case MotionEvent.ACTION_UP:
handler.removeMessages(LONG_PRESS);
break;
default:
break;
}
return true;
}
}
Even if you have a very steady hand you will likely create an
ACTION_MOVEevent:Your finger will only move a few pixels, but this is enough to remove your long press callback.
Android uses a couple static variables label
___SLOPand calculates the distance between the firstACTION_DOWNevent and the current event. Once the MotionEvent has traveled beyond the slop threshold, only then does it cancel the callback. I recommend using the same approach.