Search code examples
androidandroid-recyclerviewandroid-calendarswipe-gesture

Android Swipe gesture and item click both not working together in RecyclerView


I have calendar implemented using recyclerview. For navigation to previous and next month, as per requirement, client wants to swipe feature.

So I implemented that feature using this code:

recyclerView.setOnTouchListener(new OnSwipeTouchListener(context) {
        public void onSwipeTop() {

        }

        public void onSwipeRight() {
            onPreviousMonth();
        }

        public void onSwipeLeft() {
            onNextMonth();
        }

        public void onSwipeBottom() {

        }
    });

Using this touchListener, its working completely swipe feature for the calendar.

But after adding this feature, click of the recyclerview item not working. When I remove touch listener, click of the recyclerview item working perfectly.

What I missed in the code? Any idea? Both are not working together.

And this is OnSwipeTouchListener:

public class OnSwipeTouchListener implements OnTouchListener {

private final GestureDetector gestureDetector;

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

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

private final class GestureListener extends SimpleOnGestureListener {

    private static final int SWIPE_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) {
        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_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
                    if (diffX > 0) {
                        onSwipeRight();
                    } else {
                        onSwipeLeft();
                    }
                    result = true;
                }
            } else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
                if (diffY > 0) {
                    onSwipeBottom();
                } else {
                    onSwipeTop();
                }
                result = true;
            }
        } catch (Exception exception) {
            exception.printStackTrace();
        }
        return result;
    }
}

public void onSwipeRight() {
}

public void onSwipeLeft() {
}

public void onSwipeTop() {
}

public void onSwipeBottom() {
}

}


Solution

  • I would consider attaching an ItemTouchHelper to your RecyclerView.

    Implementation is something like this:

    new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.RIGHT | ItemTouchHelper.LEFT) {
            @Override
            public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder viewHolder1) {
                return false;
            }
    
            @Override
            public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
                if (direction == ItemTouchHelper.RIGHT) {
                    onPreviousMonth();
                } else if (direction == ItemTouchHelper.LEFT) {
                    onNextMonth();
                }
            }
        }).attachToRecyclerView(recyclerView);