Reputation: 3894
For RecyclerView
if it has not any item, then click on RecyclerView
works,
but if it has items clicking on RecyclerView
doesn't work.
Be careful I mean click on just RecyclerView
not RecyclerView
's item
recyclerView.setOnClickListener(view -> {Timber.d("recyclerView clicked");});
How I can set RecyclerView
clickable even it has items on it.
Upvotes: 6
Views: 7372
Reputation: 3037
TL;DR Java
recyclerView.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_UP)
return view.performClick();
else
return false;
}
});
recyclerView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
// do something
}
});
TL;DR Kotlin
recyclerView.setOnTouchListener { view, motionEvent ->
if (motionEvent.action == MotionEvent.ACTION_UP)
view.performClick()
else
false
}
recyclerView.setOnClickListener { view ->
// do something
}
Explanation (Java)
When the user touches the screen, the OnTouchListener
of the topmost view is triggered. Its purpose is to detect gestures (tap, long tap, swipe, etc.) and call the respective handlers. A simple tap, for example, should result in a call to the OnClickListener
.
Now, for some reason, RecyclerView
does not do that (at least it does not watch for the tap gesture) - maybe because the developers did not intend the RecyclerView
to be tapped as a whole.
So, we implement the OnTouchListener
ourselves. The easiest way would be implementing the click logic in the OnTouchListener
itself and return true
to keep the event from propagating further up in the view hierarchy:
recyclerView.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
// do something
return true
}
});
However, as the OnTouchListener
is usually invoked multiple times during a single tap on the screen, we should run our code only once after the last touch event. Furthermore, the business logic should go into the OnClickListener
which is called by performClick()
(that returns true
afterwards):
recyclerView.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_UP)
return view.performClick();
else
return false;
}
});
recyclerView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
// do something
}
});
Upvotes: 5
Reputation: 193
this code works:
recycle.setOnTouchListener { v, event ->
if(event.action == MotionEvent.ACTION_UP){
onClickListener.onClick(v)
}
false
}
Upvotes: 0
Reputation: 788
Just use setOnTouchListener
instead of setOnClickListener
.
It works for me . . .
recyclerView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
//Do anyThing you need
return false;
}
});
Upvotes: 3
Reputation: 81
Try to extend RecyclerView
and Override onInterceptTouchEvent
. Also make it always return true. Then use OnTouch
instead of OnClickListener
Here are some of code.
public class MyRecyclerView extends RecyclerView {
public MyRecyclerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
return true;
}
}
Activity.class
recyclerView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Toast.makeText(MainActivity.this,"RecyclerView",Toast.LENGTH_SHORT).show();
return false;
}
});
Upvotes: 5
Reputation: 1853
Because nobody had answered the actual question itself yet..
My solution was to put a empty View on top of the RecyclerView withing ConstraintLayout such as
<androidx.recyclerview.widget.RecyclerView
app:layout_constraintTop_toBottomOf="@+id/toolbar"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="0dp">
</androidx.recyclerview.widget.RecyclerView>
<View
android:id="@+id/touch_overlay"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="@+id/recycler_view"
app:layout_constraintStart_toStartOf="@+id/recycler_view"
app:layout_constraintEnd_toEndOf="@+id/recycler_view"
app:layout_constraintBottom_toBottomOf="@+id/recycler_view"/>
then I would set the onClickListener on the touch_overlay and it would work as expected.
On the Java/Kotlin side its as expected
binding.touchOverlay.setOnClickListener {
Toast.makeText(context, "clicked recyclerView", Toast.LENGTH_LONG).show()
}
On the other hand, more lightweight solution, especially when not using ConstraintLayout is to use a FrameLayout, then place an empty View on top of the RecyclerView that would receive the clicks
Upvotes: 0
Reputation: 62189
but if it has items clicking on RecyclerView doesn't work
Why do you think that you are performing a click on the RecyclerView
itself?
Most possibly the item of the RecyclerView
swallows the touch event, thus it won't be reached to the RecyclerView
. You can make the children of RecyclerView
to be not clickable, then the next item that would be given a chance to respond to click event would be the RecyclerView
.
Upvotes: 1