Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android: Detect ACTION_UP event outside button

I'm having some problem with a custom button I built. It consist of a box and a small line below it.

The button animates down vertically when you press on it and up again when you release. This is handled in the CustomButton.class:

super.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
                    buttonContent.startAnimation(rectMoveDown);
                    colorDown.start();
                    return false;
                }
                if (event.getActionMasked() == MotionEvent.ACTION_UP) {
                    buttonContent.startAnimation(rectMoveUp);
                    colorUp.start();
                    return false;
                }
                return false;
            }
        });

Then in the rest of the application I use this button and set a clicklistener to it. Therefore I return false (I think that is correct at least) since I do not want to consume the event, but pass it on to the clicklistener in the hierarchy.

However, the problem emerge when I first press down on the button, move my finger outside the button and then release the screen. Then the button do not show the animation done in the ACTION_UP listener.

Does anyone have a clue how to fix this?

like image 770
Andreas Rolén Avatar asked Jul 28 '15 11:07

Andreas Rolén


1 Answers

Found out how I could solve it after some more testing!

After reading some more in the documentation I found that MotionEvent.ACTION_CANCEL does exactly what I need:

The current gesture has been aborted. You will not receive any more points in it. You should treat this as an up event, but not perform any action that you normally would.

So now my TouchListener look like this (and works like it should):

super.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getActionMasked()) {
                    case MotionEvent.ACTION_DOWN:
                        buttonContent.startAnimation(rectMoveDown);
                        colorDown.start();
                        return false;
                    case MotionEvent.ACTION_UP:
                    case MotionEvent.ACTION_CANCEL:
                        buttonContent.startAnimation(rectMoveUp);
                        colorUp.start();
                        return false;
                }
                return false;
            }
        });

It was not that I started to use the switch-case that solved it, but I changed to it in order to make the code look better. As you can see I handle the ACTION_UP and the ACTION_CANCEL in the exact same way.

I return false everywhere in order for the OnClickListener to trigger which it wouldn't if I returned true.

like image 94
Andreas Rolén Avatar answered Nov 04 '22 17:11

Andreas Rolén