I was following this tutorial and tried to use multiple ViewHolders. An example use case would be a messaging app where the recyclerview has to display a sent message and a receiving message with different layouts. I got it working with the following solution:
class MyEntityDiffCallback : DiffUtil.ItemCallback<MyEntity>() {
override fun areItemsTheSame(oldItem: MyEntity, newItem: MyEntity): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: MyEntity, newItem: MyEntity): Boolean {
return oldItem == newItem
}
}
class MyAdapter :
ListAdapter<MyEntity, MyAdapter.MyAbstractViewHolder>(
MyEntityDiffCallback()
) {
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): MyAbstractViewHolder {
if (viewType == 1){
return MyViewHolder1.from(parent)
}else{
return MyViewHolder2.from(parent)
}
}
override fun onBindViewHolder(holder: MyAbstractViewHolder, position: Int) {
val item = getItem(position)
holder.bind(item)
}
override fun getItemViewType(position: Int): Int {
val item = getItem(position)
if(item.someCounter > 5){
return 1
}else{
return 0
}
}
abstract class MyAbstractViewHolder(val binding: ViewDataBinding) :
RecyclerView.ViewHolder(binding.root) {
abstract fun bind(item: MyEntity)
}
class MyViewHolder2 private constructor(binding: Item2Binding) :
MyAbstractViewHolder(binding) {
override fun bind(
item: MyEntity
) {
val binding = binding as Item2Binding
binding.message = item
binding.executePendingBindings()
}
companion object {
fun from(parent: ViewGroup): MyViewHolder2 {
val layoutInflater = LayoutInflater.from(parent.context)
val binding =
Item2Binding.inflate(layoutInflater, parent, false)
return MyViewHolder2(binding)
}
}
}
class MyViewHolder1 private constructor(binding: Item1Binding) :
MyAbstractViewHolder(binding) {
override fun bind(
item: MyEntity
) {
val binding = binding as Item1Binding
binding.message = item
binding.executePendingBindings()
}
companion object {
fun from(parent: ViewGroup): MyViewHolder1 {
val layoutInflater = LayoutInflater.from(parent.context)
val binding =
Item1Binding.inflate(layoutInflater, parent, false)
return MyViewHolder1(binding)
}
}
}
}
Is this the way it should be implemented? I am not sure about the cast of the binding value in the bind method. Or are there other good practices to solve this with the Listadapter and the Databinding?