Is there any way to set an onClickListener
on a RecyclerView
?
I have a RecyclerView
with some children in it, and setting an <
Here is a trick, It's open for comments.
You can have 2 children items in a FrameLayout
. The first being the RecyclerView
and the second a View
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<View
android:id="@+id/over_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</FrameLayout>
Since its a FrameLayout
the View
would be on top of the RecyclerView
and you can set an onClickListener
to the View
and it would behave as if it was the RecyclerView
that was clicked
over_view.setOnClickListener {
.....
}
Is there any way to set an
onClickListener
on aRecyclerView
?
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 MotionEvent
s 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 {
this@enableClickListener.performClick()
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 :)
a click event on RecycleView ? try like this:
//set android:descendantFocusability="blocksDescendants" on parent layout
//then setOnClickListener
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
**android:descendantFocusability="blocksDescendants"**
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
</LinearLayout>