Search code examples
androidandroid-recyclerviewkotlinonclicklisteneronitemclicklistener

Can we make use of the built in setOnClickListener on RecyclerView row item instead of custom item click listener?


I have seen many examples for providing click functionality (for selecting row item in recycler view) to a row item, but all of them are using custom click listener class to achieve this. Is there any method to achieve this click functionality?


Solution

  • Detecting click on a RecyclerView item is very easy. All you need to do is define an interface (if you're not using Kotlin, in which case you just pass in a lambda):

    public class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {
        private final Clicks clicks;
    
        public MyAdapter(Clicks clicks) {
            this.clicks = clicks;
        }
    
        private List<MyObject> items = Collections.emptyList();
    
        public void updateData(List<MyObject> items) {
            this.items = items;
            notifyDataSetChanged(); // TODO: use ListAdapter for diffing instead if you need animations
        }
    
        public interface Clicks {
            void onItemSelected(MyObject myObject, int position);
        }
    
        public class MyViewHolder extends RecyclerView.ViewHolder {
            private MyObject myObject;    
    
            public MyViewHolder(View view) {
                super(view);
                // bind views
                view.setOnClickListener((v) -> {
                    int adapterPosition = getAdapterPosition();
                    if(adapterPosition >= 0) {
                        clicks.onItemSelected(myObject, adapterPosition);
                    }
                });
            }
    
            public void bind(MyObject myObject) {
                this.myObject = myObject;
                // bind data to views
            }
        }
    }
    

    Same code in Kotlin:

    class MyAdapter(val itemClicks: (MyObject, Int) -> Unit): RecyclerView.Adapter<MyViewHolder>() {
        private var items: List<MyObject> = Collections.emptyList()
    
        fun updateData(items: List<MyObject>) {
            this.items = items
            notifyDataSetChanged() // TODO: use ListAdapter for diffing instead if you need animations
        }
    
        inner class MyViewHolder(val myView: View): RecyclerView.ViewHolder(myView) {
            private lateinit var myObject: MyObject
    
            init {
                // binds views
                myView.onClick {
                    val adapterPosition = getAdapterPosition()
                    if(adapterPosition >= 0) {
                        itemClicks.invoke(myObject, adapterPosition)
                    }
                }
            }
    
            fun bind(myObject: MyObject) {
                this.myObject = myObject
                // bind data to views
            }
        }
    }