The correct way to use multiple Viewholders in Listadapter
Asked Answered
S

0

11

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?

Sevastopol answered 26/2, 2021 at 1:56 Comment(1)
check this. I don't if it works or not. medium.com/@vivekvashistha/…Rope

© 2022 - 2024 — McMap. All rights reserved.