Question

I have a button that I'm animating on button press. I want it to snap back to its "normal" state after I drag outside a certain threshold.

I create a rectangle of the view bounds on ACTION_DOWN and check whether it's out of the touch area in ACTION_MOVE. I successfully detect the "out of bounds" touch, but I can't get the view to stop listening to touches. It's like it ignores my animateToNormal() method.

I've tried changing the boolean return value to true instead of false, which didn't help. I've also tried removing the touch listener in the ACTION_MOVE case (set null), but I need to re-attach to continue listening to touches. I figure I can add an arbitrary delay before adding it back, but that seems like a terrible hack.

I'm testing this on a 4.2 device (LG G2).

private static class AnimationOnTouchListener implements View.OnTouchListener {
        private Rect rect;

        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {

            switch(motionEvent.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    rect = new Rect(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
                    animatePressed();
                    return false;

                case MotionEvent.ACTION_CANCEL:
                case MotionEvent.ACTION_UP:
                    // back to normal state
                    animateBackToNormal();
                    return false;

                case MotionEvent.ACTION_MOVE:
                    if(!rect.contains(view.getLeft() + (int) motionEvent.getX(), view.getTop() + (int) motionEvent.getY())){
                        d(TAG, "out of bounds");
                        animateBackToNormal();
                        // STOP LISTENING TO MY TOUCH EVENTS!

                    } else {
                        d(TAG, "in bounds");
                    }
                    return false;
                default:
                    return true;
            }
        }
Was it helpful?

Solution

Why you just don't keep listening but set an statement to ignore the motion event?

Something like that:

private static class AnimationOnTouchListener implements View.OnTouchListener {
        private Rect rect;
        private boolean ignore = false;

    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        if(ignore && motionEvent.getAction()!=MotionEvent.ACTION_UP)
           return false;
        switch(motionEvent.getAction()) {
            case MotionEvent.ACTION_DOWN:
                rect = new Rect(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
                animatePressed();
                return false;

            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                // back to normal state
                animateBackToNormal();

                // IMPORTANT - touch down won't work if this isn't there.
                ignore = false;
                return false;

            case MotionEvent.ACTION_MOVE:
                if(!rect.contains(view.getLeft() + (int) motionEvent.getX(), view.getTop() + (int) motionEvent.getY())){
                    d(TAG, "out of bounds");
                    animateBackToNormal();
                    // STOP LISTENING TO MY TOUCH EVENTS!
                    ignore = true;
                } else {
                    d(TAG, "in bounds");
                }
                return false;
            default:
                return true;
        }
    }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top