How to get clicks on RecyclerView (NOT the children)

Is there any way to set an onClickListener on a RecyclerView?

No. That is, you can set an OnClickListener, but RecyclerView will never call it. RecyclerView intercepts all touch events, but never calls performClick(), which is how View invokes its listener.

You can, however, simulate an OnClickListener with an OnTouchListener and a GestureDetector. For the GestureDetector's listener, we can use a SimpleOnGestureListener, implementing just the onSingleTapUp() method.

class ClickListener extends GestureDetector.SimpleOnGestureListener {
    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        Toast.makeText(HelloActivity.this, "Clicked", 0).show();
        return true;
    }
};

Then we just need to feed the GestureDetector the MotionEvents from an OnTouchListener, and check the return to decide whether to consume the event, so as to not interfere with scrolling, dragging, etc.

final GestureDetector detector = new GestureDetector(HelloActivity.this, new ClickListener());

mRecyclerView.setOnTouchListener(new OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if(detector.onTouchEvent(event)) {
                return true;
            }
            return false;
        }
    }
);

Please note that the above solution works with pretty much only a "simple" RecyclerView, like the one described and given in the question. If you're using more involved item handling, like drag and drop or swipe, we'll need to handle our gesture detection a little further up the touch event chain.

To do this, we can subclass RecyclerView and perform the detection in the dispatchTouchEvent() method. If a single tap is detected, we simply call performClick(), which will fire the RecyclerView's OnClickListener.

public class ClickableRecyclerView extends RecyclerView {

    private final GestureDetectorCompat detector;

    public ClickableRecyclerView(Context context) {
        this(context, null);
    }

    public ClickableRecyclerView(Context context, AttributeSet attrs) {
        super(context, attrs);
        detector = new GestureDetectorCompat(context, new ClickListener());
    }

    private class ClickListener extends GestureDetector.SimpleOnGestureListener {
        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            performClick();
            return true;
        }
    };

    @Override
    public boolean dispatchTouchEvent(MotionEvent e) {
        detector.onTouchEvent(e);
        return super.dispatchTouchEvent(e);
    }
}

Just use this subclass in place of your regular RecyclerView, and set an OnClickListener on it as you normally would. Additional constructors may be necessary, depending on how you're instantiating this.


This is how I have done in Kotlin style

fun RecyclerView.enableClickListener(){
    val gesture = object : GestureDetector.SimpleOnGestureListener(){
        override fun onSingleTapConfirmed(e: MotionEvent?): Boolean {
            [email protected]()
            return super.onSingleTapConfirmed(e)
        }
    }
    val detector = GestureDetector(this.context, gesture)
    this.setOnTouchListener { v, event -> detector.onTouchEvent(event) }
}

And this is how to use it

yourRecyclerView.apply {
        enableClickListener()
        setOnClickListener {
           // Do what you want  ...
        }
    }

Enjoy :)