I have a UX requirement that the user triggers a Dialog
by long pressing a cell in a GridView
.
While the Dialog
is displayed the user must be able to move their finger/thumb around the screen without triggering the UP/CANCEL
event when they leave the bounds of GridView
cell.
When the user finally breaks contact with the screen is what I'm looking to capture. GridView
seems to register some false positives for UP/CANCEL
that we don't see using any other views.
The issue is that the original view captures all the touch events because the DOWN
was captured by it.
The dialog registers/sees no touches until after the UP event from the original view.
I have tried cancelling the original touch event and using dispatchTouch()
, etc. No joy.
Any ideas?
I have used something like this in one of my projects.
Assign an OnTouchListener
to every cell of your gridView and override the OnTouch method.
@Override
public boolean onTouch(View v, MotionEvent event) {
boolean isLongPressed;
int mSwipeSlop = ViewConfiguration.get(context).
getScaledTouchSlop();
boolean mSwiping;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
handler.postDelayed(mLongPressed, 1000);
break;
case MotionEvent.ACTION_CANCEL:
handler.removeCallbacks(mLongPressed);
break;
case MotionEvent.ACTION_MOVE:
float x = event.getX() + v.getTranslationX();
float deltaX = x - mDownX;
float deltaXAbs = Math.abs(deltaX);
float y = event.getY() + v.getTranslationY();
float deltaY = Y - mDownY;
float deltaYAbs = Math.abs(deltaY);
float absDist = Math.sqrt(Math.pow(deltaXAbs, 2) + Math.pow(deltaXAbs, 2));
if (!mSwiping) {
if (absDist > mSwipeSlop) {
mSwiping = true;
handler.removeCallbacks(mLongPressed);
}
}
break;
case MotionEvent.ACTION_UP:
handler.removeCallbacks(mLongPressed);
if (isLongPressed) {
// DO ACTION UP
}
break;
default:
return false;
}
return true;
}
Open the dialog in the runnable mLongPressed, which will only run if the user has touched the same spot for a second. You can change the distance he can move and the time he needs to press to register as a long click of course. However, I would recommend using getScaledTouchSlop() for the distance.
final Handler handler = new Handler();
Runnable mLongPressed = new Runnable() {
public void run() {
// OPEN DIALOG
isLongPressed = true;
}
};
By using this code in my project, the user can move his finger around the whole screen without ACTION_UP getting triggered. Only when he lifts his finger, it is triggered.