0

Android Studio, Java

Is there a way to detect touch down, touch release, and swipe gestures, on a single view? I have a button and I need to be able to listen to all of these on it.

I'm looking for a solution where the listeners/detectors end up calling these methods so I easily can work with them:

public void buttonPressedDown() {

}

public void buttonReleased() {

}

public void swipeUp() {

}

public void swipeRight() {

}

public void swipeDown() {

}

public void swipeLeft() {

}

This is easy to accomplish in xcode when developing ios apps, but I can't seem to find a way to do it for android.

Extra info: This is what I've tried:

    timerButton.setOnTouchListener(new View.OnTouchListener() { //Detecting a press down
        @Override
        public boolean onTouch(View v, MotionEvent event) {

            timerDown();

            return false;
        }
    });

    timerButton.setOnTouchListener(new OnSwipeTouchListener(timerActivity.this) {//Detecting swipes

        public void onSwipeTop() {

            showStats();

        }

        public void onSwipeBottom() {

            showType();

        }

        public void onSwipeRight() {

            showMenu();

        }

        public void onSwipeLeft() {

            showTimes();

        }

    });


    .
    .
    .


    public void timerButtonPressed(View view) {//Detecting press releases
        timerUp();
    }

This seemed like what I was looking for, except it didn't work. When setting two onTouchListeners on the same view, only one of the listeners were being called. Either only the swipe detections worked, or only the press detections, when I tested it.

Help!?

Edit: I've tried this:

OnSwipeTouchListener.java

public class OnSwipeTouchListener implements View.OnTouchListener {

    private final GestureDetector gestureDetector;

    public OnSwipeTouchListener(Context context) {
        gestureDetector = new GestureDetector(context, new GestureListener());
    }

    public void onSwipeLeft() {
    }

    public void onSwipeRight() {
    }

    public boolean onTouch(View v, MotionEvent event) {
        return gestureDetector.onTouchEvent(event);
    }

    private final class GestureListener extends GestureDetector.SimpleOnGestureListener {

        private static final int SWIPE_DISTANCE_THRESHOLD = 100;
        private static final int SWIPE_VELOCITY_THRESHOLD = 100;

        @Override
        public boolean onDown(MotionEvent e) {
            return true;
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            float distanceX = e2.getX() - e1.getX();
            float distanceY = e2.getY() - e1.getY();
            if (Math.abs(distanceX) > Math.abs(distanceY) && Math.abs(distanceX) > SWIPE_DISTANCE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
                if (distanceX > 0)
                    onSwipeRight();
                else
                    onSwipeLeft();
                return true;
            }
            return false;
        }
    }
}

And in my activity:

timerButton.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {

            OnSwipeTouchListener onSwipeTouchListener = new OnSwipeTouchListener(timerActivity.this);
            boolean result = onSwipeTouchListener.onTouch(v, event);
            // check if swipe was detected:
            if (result) return true;

            // Otherwise, detect other types of motion event
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    // touch down

                    timerDown();

                    break;
                case MotionEvent.ACTION_UP:
                    // touch released

                    timerUp();

                    break;
            }

            return false;
        }
    });

But how would I detect the swipes from here? Also when I run the application it doesn't even detect touches anymore.

I also tried this in my activity:

timerButton.setOnTouchListener(new OnSwipeTouchListener(timerActivity.this) {

        public void onSwipeLeft() {
            Log.i("LEFT", "LEFT");
        }

        public void onSwipeRight() {
            Log.i("RIGHT", "RIGHT");
        }

        @Override
        public boolean onTouch(View v, MotionEvent event) {

            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    // touch down

                    timerDown();

                    break;
                case MotionEvent.ACTION_UP:
                    // touch released

                    timerUp();

                    break;
            }

            return false;
        }
    });

Now it detects touches but won't detect swipes. If I remove the @override onTouch method above, but still have the onSwipe methods, then the swipes are detected. How is this so complicated? Why won't it detect both swipes and touches, and how do I solve it?

2 Answers2

4

I found a solution.

In OnSwipeTouchListener.java:

public class OnSwipeTouchListener implements View.OnTouchListener {

private final GestureDetector gestureDetector;

public OnSwipeTouchListener(Context context) {
    gestureDetector = new GestureDetector(context, new GestureListener());
}

public void onSwipeLeft() {
}

public void onSwipeRight() {
}

public void onSwipeBottom() {
}

public void onSwipeTop() {
}

public void onDownTouch() {

}

public boolean onTouch(View v, MotionEvent event) {
    return gestureDetector.onTouchEvent(event);
}

private final class GestureListener extends GestureDetector.SimpleOnGestureListener {

    private static final int SWIPE_DISTANCE_THRESHOLD = 100;
    private static final int SWIPE_VELOCITY_THRESHOLD = 100;

    @Override
    public boolean onDown(MotionEvent e) {
        onDownTouch();
        return false;
    }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        boolean result = false;
        try {
            float diffY = e2.getY() - e1.getY();
            float diffX = e2.getX() - e1.getX();
            if (Math.abs(diffX) > Math.abs(diffY)) {
                if (Math.abs(diffX) > SWIPE_DISTANCE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
                    if (diffX > 0) {
                        onSwipeRight();
                    } else {
                        onSwipeLeft();
                    }
                    result = true;
                }
            }
            else if (Math.abs(diffY) > SWIPE_DISTANCE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
                if (diffY > 0) {
                    onSwipeBottom();
                } else {
                    onSwipeTop();
                }
                result = true;
            }
        } catch (Exception exception) {
            exception.printStackTrace();
        }
        return result;
    }
}

}

And in activity:

To detect button release press: (on click)

public void timerButtonPressed(View view) {

}

To detect swipes and down press:

timerButton.setOnTouchListener(new OnSwipeTouchListener(timerActivity.this) {

        public void onSwipeLeft() {

        }

        public void onSwipeRight() {

        }

        public void onSwipeBottom() {

        }

        public void onSwipeTop() {

        }

        public void onDownTouch() {

        }
    });
0

Calling setOnTouchListener the second time overwrites your previous listener. You can detect both touches and gestures by:

timerButton.setOnTouchListener(new View.OnTouchListener() { 
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            // deliver motion event to your swipe listener
            boolean result = mySwipeListener.onTouch(event);
            // check if swipe was detected:
            if (result) return true;

            // Otherwise, detect other types of motion event
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    // touch down
                    break;
                case MotionEvent.ACTION_UP:
                    // touch released
                    break;
                // etc... see this link for more motion events https://developer.android.com/reference/android/view/MotionEvent
            }

            return false;
        }
    });

Here's an example on implementing on swipe listener: Android: How to handle right to left swipe gestures

Christilyn Arjona
  • 2,173
  • 3
  • 13
  • 20
  • Good idea! Tried it but it didn't really work. I would need more details. Mostly on how to detect the swipes, because now the code only checks if there was a swipe or not. – dominobuilder100 Jan 07 '20 at 14:03