3

I want to be able to detect a single click or a double click when the menu button is pressed. If a single click is detected one even will happen, if a double click is detected a different event will happen. Here is what I've tried(Using toast in place of events):

private static final long DOUBLE_PRESS_INTERVAL = 250; // in millis
private long lastPressTime;

@Override
public boolean onPrepareOptionsMenu(Menu menu) {    

    // Get current time in nano seconds.
    long pressTime = System.currentTimeMillis();


    // If double click...
    if (pressTime - lastPressTime <= DOUBLE_PRESS_INTERVAL) {
        Toast.makeText(getApplicationContext(), "Double Click Event", Toast.LENGTH_SHORT).show();
        return true;
    }

    // If not double click....
    Toast.makeText(getApplicationContext(), "Single Click Event", Toast.LENGTH_SHORT).show();

    // record the last time the menu button was pressed.
    lastPressTime = pressTime;      
    return true;
}

The problem is that a single click event is detected every time before a double click event.

Shaeldon
  • 873
  • 4
  • 18
  • 28
jjNford
  • 5,170
  • 7
  • 40
  • 64
  • how do i detected a long click? am digging through documentation right now but not finding anything that works? (doing a long click right now just displays the keyboard) – jjNford Sep 01 '11 at 14:16
  • i think i see what you are saying. i want the long click on the physical keyboard not the view. the view already has a registered long click. – jjNford Sep 01 '11 at 14:26

2 Answers2

15

Simple logic mistake. You are returning before recording the new lastPressTime. You should only have one return call if they are both returning the same thing:

boolean mHasDoubleClicked = false;

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {    

        // Get current time in nano seconds.
        long pressTime = System.currentTimeMillis();


        // If double click...
        if (pressTime - lastPressTime <= DOUBLE_PRESS_INTERVAL) {
            Toast.makeText(getApplicationContext(), "Double Click Event", Toast.LENGTH_SHORT).show();
            mHasDoubleClicked = true;
        }
        else {     // If not double click....
            mHasDoubleClicked = false;
            Handler myHandler = new Handler() {
                 public void handleMessage(Message m) {
                      if (!mHasDoubleClicked) {
                            Toast.makeText(getApplicationContext(), "Single Click Event", Toast.LENGTH_SHORT).show();
                      }
                 }
            };
            Message m = new Message();
            myHandler.sendMessageDelayed(m,DOUBLE_PRESS_INTERVAL);
        }
        // record the last time the menu button was pressed.
        lastPressTime = pressTime;      
        return true;
    }
Ian
  • 3,500
  • 1
  • 24
  • 25
  • 1
    This will not fix the problem because the first time that the button is pressed in the double click you will run the 'else' case and toast the single click event, followed immediately by the 'if' case. – jjNford Sep 01 '11 at 14:09
  • ah ok i get it now. See if the edit if better. I haven't check to see if it compiles. – Ian Sep 01 '11 at 14:22
  • missing a single semicolon after the handleMessage declaration. but it works perfect. awesome! have never used a handler object and never found anything about it when searching google for an answer to this problem. thanks a ton! – jjNford Sep 01 '11 at 14:32
2

I modified this code to detect hold events (long clicks) as well as short and double clicks. It works by delaying detection of a short click until an ACTION_UP event, where the event has not already been handled (clickHandled == false).

Provide your own methods for onShortClick(), onLongClick() and and onDoubleClick().

private long thisTouchTime;
private long previousTouchTime = 0;
private long buttonHeldTime;
private boolean clickHandled = false;
private long DOUBLE_CLICK_INTERVAL = ViewConfiguration.getDoubleTapTimeout();
private long LONG_HOLD_TIMEOUT = ViewConfiguration.getLongPressTimeout();

@Override
public boolean onTouch(View v, final MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            thisTouchTime = System.currentTimeMillis();
            if (thisTouchTime - previousTouchTime <= DOUBLE_CLICK_INTERVAL) {
                // double click detected
                clickHandled = true;
                onDoubleClick(event);
            } else {
                // defer event handling until later
                clickHandled = false;
            }
            previousTouchTime = thisTouchTime;
            break;
        case MotionEvent.ACTION_UP:
            if (!clickHandled) {
                buttonHeldTime = System.currentTimeMillis() - thisTouchTime;
                if (buttonHeldTime > LONG_HOLD_TIMEOUT) {
                    clickHandled = true;
                    onLongClick(event);
                } else {
                    Handler myHandler = new Handler() {
                        public void handleMessage(Message m) {
                            if (!clickHandled) {
                                clickHandled = true;
                                onShortClick(event);
                            }
                        }
                    };
                    Message m = new Message();
                    myHandler.sendMessageDelayed(m, DOUBLE_CLICK_INTERVAL);
                }
            }
            break;
        case MotionEvent.ACTION_MOVE:
            myParams.x = initialDrawX + (int) (event.getRawX() - initialTouchX);
            myParams.y = initialDrawY + (int) (event.getRawY() - initialTouchY);
            windowManager.updateViewLayout(v, myParams);
            break;
    }
    return false;
}
regas
  • 31
  • 1