sagar.android
sagar.android

Reputation: 1870

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() {
}

}

Upvotes: 0

Views: 2107

Answers (3)

MidasLefko
MidasLefko

Reputation: 4559

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);

Upvotes: 1

Anjan Debnath
Anjan Debnath

Reputation: 120

You should make sure that the TouchListener is not consuming the touch event. If you return true from the onTouch() method, Android will consider it consumed and not pass it on to the other various touch handlers (which I am assuming will include the ClickListener).

Upvotes: 0

Hardik Chauhan
Hardik Chauhan

Reputation: 2746

You can add logic like this,

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

        switch (event.getAction()) {

            case MotionEvent.ACTION_DOWN:
                x1 = event.getX();
                y1 = event.getY();
                t1 = System.currentTimeMillis();
                return true;
            case MotionEvent.ACTION_UP:
                x2 = event.getX();
                y2 = event.getY();
                t2 = System.currentTimeMillis();

                if (x1 == x2 && y1 == y2 && (t2 - t1) < DURATION_TO_CONSIDER_CLICK) {
                    // Consider as normal click or tap
                } else if ((t2 - t1) >= DURATION_TO_CONSIDER_CLICK) {
                    // Consider as long click or tap
                } else if (x1 > x2) {
                    // Consider as left swipe
                } else if (x2 > x1) {
                    // Consider as right swipe
                } 
                return true;
        }
        return false;
    }

Please note that this is just for the reference, you might need to change the above logic as bit to fulfill your expectation. Thanks.

Upvotes: 0

Related Questions