· 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)
}
}
}