A RecyclerView with multiple item types in Kotlin
It's been already 7 years ago that I wrote this article about multiple RecyclerView item types.
It got quite some views and responses, so I thought it would be nice to write a Kotlin version of this mini tutorial. You will see that it's a lot more compact than the old Java version.
So, here we go… Let's start with an interface for all the data types we have!
interface ListItem {
enum class Type(value: Int) {TypeA(0), TypeB(1) }
fun getListItemType(): Int
}
I'm still a bit in doubt if a sealed class would be a more elegant solution, but let's use an enum for now. We have a TypeA and a TypeB implementation and they look like this.
data class ItemA(val textA: String): ListItem {
override fun getListItemType(): Int {
return ListItem.Type.TypeA.ordinal
}
}
And here is our Adapter!
class ItemAdapter(private val items: List<ListItem>) : RecyclerView.Adapter<BaseViewHolder>() {
override fun getItemViewType(position: Int): Int {
return items[position].getListItemType()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder {
return when (viewType) {
ListItem.Type.TypeA.ordinal -> {
val view = LayoutInflater.from(parent.context).inflate(R.layout.itemview_a, parent, false)
return ViewHolderA(view)
}
ListItem.Type.TypeB.ordinal -> {
val view = LayoutInflater.from(parent.context).inflate(R.layout.itemview_b, parent, false)
return ViewHolderB(view)
}
else -> {
val view = LayoutInflater.from(parent.context).inflate(R.layout.itemview_a, parent, false)
return ViewHolderB(view)
}
}
}
override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
holder.bind(items[position])
}
override fun getItemCount(): Int {
return items.size
}
}
I am not very happy with the fact that the onCreateViewHolder() function needs an else-statement which never will be reached. But since the RecyclerView is implemented with viewType as an Int I think we don't really have another option. But please leave a comment if you have a better solution for this!
Last but not least we need a ViewHolder abstraction. I made a BaseViewHolder with an abstract bind() function.
abstract class BaseViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
abstract fun bind(item: ListItem)
}
And here's an example ViewHolder implementation.
class ViewHolderA(itemView: View) : BaseViewHolder(itemView) {
private val textView: TextView = itemView.findViewById(R.id.text)
override fun bind(item: ListItem) {
val itemA = item as ItemA
textView.text = itemA.textA
}
}
Let me know what you think!