· 3 min read

Set a click listener to a RecyclerView

If you’ve used a RecyclerView, you may know that they don’t have a setOnItemClickListener as ListView had, so we have to create our own way to do it. Many people asked me how to do this, so that’s why I decided to write about it.

There are many ways to achieve this, but I will show you the way I usually do it. My mechanism consists of passing the listener as a parameter to the constructor and then assign it when I bind the data to the view in onBindViewHolder.

In Java, you would need an interface that specifies listener’s behaviour. In this example, there is a sample model called ContentItem, so the click will return an item of that type:

public interface OnItemClickListener {
    void onItemClick(ContentItem item);
}

In Kotlin you don’t need this. You can’t just use a lambda to get the same result. We’ll see it in a minute.

If you haven’t, I encourage you to learn Kotlin, because nowadays is the present of Android! Android is Kotlin first. I recommend you to join my free masterclass so that you can easily start with it.

The constructor will receive a lambda that represents the listener, along with the items to be rendered:

class ContentAdapter(
    private val items: List<ContentItem>,
    private val listener: (ContentItem) -> Unit
) : RecyclerView.Adapter<ViewHolder>()

You could alternatively create a setOnItemClickListener method and assign it that way. Now, in onBindViewHolder the view is assigned with this click listener:

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    val item = items[position]
    holder.bind(item)
    holder.itemView.setOnClickListener { listener(item) }
}

Use it whenever you need it by creating a new adapter and the listener that will implement the behaviour when an item is clicked. A simple example:

recycler.adapter = ContentAdapter(items) { item ->
    toast(item.title)
}

If you want to know how this toast extension function is created, go check out my article about extension functions in Kotlin.

Take a look at the whole code of this adapter. Of course there are many alternatives here. In the end, the implementation is left to the developer when using RecyclerView, so choose whatever fits better in your situation.

class ContentItem(val name: String, val imageUrl: String)

class ContentAdapter(
    private val items: List<ContentItem>,
    private val listener: (ContentItem) -> Unit
) : RecyclerView.Adapter<ContentAdapter.ViewHolder>() {

    override fun onCreateViewHolder(
        parent: ViewGroup,
        viewType: Int
    ): ViewHolder {
        val v = parent.inflate(R.layout.view_item)
        return ViewHolder(v)
    }

    override fun onBindViewHolder(
        holder: ViewHolder,
        position: Int
    ) {
        val item = items[position]
        holder.bind(item)
        holder.itemView.setOnClickListener { listener(item) }
    }
    
    override fun getItemCount(): Int {
        return items.size
    }

    class ViewHolder(itemView: View) : 
            RecyclerView.ViewHolder(itemView) {

        private val name = itemView.findViewById<TextView>(R.id.name)
        private val image = itemView.findViewById<ImageView>(R.id.image)

        fun bind(item: ContentItem) {
            name.text = item.name
            image.loadUrl(item.imageUrl)
        }

    }

}
    Share:
    Back to Blog