Mehrdad Faraji
Mehrdad Faraji

Reputation: 3894

setOnClickListener for recyclerView not working

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

Answers (6)

Tobias Uhmann
Tobias Uhmann

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

xiaoyuan hu
xiaoyuan hu

Reputation: 193

this code works:

  recycle.setOnTouchListener { v, event ->
                if(event.action == MotionEvent.ACTION_UP){
                    onClickListener.onClick(v)
                }
                false
            }

Upvotes: 0

elyar abad
elyar abad

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

leo liao
leo liao

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

Pasi Matalamäki
Pasi Matalamäki

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

azizbekian
azizbekian

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

Related Questions