Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Registering UP/CANCEL from Dialog when DOWN event was triggered from a View's LongPress

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?

like image 852
Bill Mote Avatar asked Oct 21 '14 15:10

Bill Mote


1 Answers

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.

like image 154
Robbe Avatar answered Sep 30 '22 16:09

Robbe