Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use ViewBinding in a RecyclerView.Adapter?

Can I use ViewBindings to replace findViewById in this typical RecyclerView.Adapter initialization code? I can't set a binding val in the object as the ViewHolders are different per cell.

class CardListAdapter(private val cards: LiveData<List<Card>>) : RecyclerView.Adapter<CardListAdapter.CardViewHolder>() {      class CardViewHolder(val cardView: View) : RecyclerView.ViewHolder(cardView)      override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CardViewHolder {         val binding = CardBinding.inflate(LayoutInflater.from(parent.context), parent, false)         return CardViewHolder(binding.root)     }      override fun onBindViewHolder(holder: CardViewHolder, position: Int) {         val title = holder.cardView.findViewById<TextView>(R.id.title)         val description = holder.cardView.findViewById<TextView>(R.id.description)         val value = holder.cardView.findViewById<TextView>(R.id.value)         // ...     } 
like image 517
A1m Avatar asked Feb 26 '20 22:02

A1m


People also ask

How do I set my adapter binding?

To create a custom binding adapter, you need to create an extension function of the view that will use the adapter. Then, you add the @BindingAdapter annotation. You have to indicate the name of the view attribute that will execute this adapter as a parameter in the annotation.


2 Answers

What you need to do is pass the generated binding class object to the holder class constructor. In below example, I have row_payment XML file for RecyclerView item and the generated class is RowPaymentBinding so like this

    class PaymentAdapter(private val paymentList: List<PaymentBean>) : RecyclerView.Adapter<PaymentAdapter.PaymentHolder>() {         override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PaymentHolder {             val itemBinding = RowPaymentBinding.inflate(LayoutInflater.from(parent.context), parent, false)             return PaymentHolder(itemBinding)         }              override fun onBindViewHolder(holder: PaymentHolder, position: Int) {             val paymentBean: PaymentBean = paymentList[position]             holder.bind(paymentBean)         }              override fun getItemCount(): Int = paymentList.size              class PaymentHolder(private val itemBinding: RowPaymentBinding) : RecyclerView.ViewHolder(itemBinding.root) {             fun bind(paymentBean: PaymentBean) {                 itemBinding.tvPaymentInvoiceNumber.text = paymentBean.invoiceNumber                 itemBinding.tvPaymentAmount.text = paymentBean.totalAmount             }         }     } 

Also, make sure you pass the root view to the parent class of Viewholder like this RecyclerView.ViewHolder(itemBinding.root) by accessing the passed binding class object.

like image 169
Somesh Kumar Avatar answered Oct 06 '22 00:10

Somesh Kumar


Attach the binding to the ViewHolder instead of the View

class CardViewHolder(val binding: CardBinding) : RecyclerView.ViewHolder(binding.root) 

You pass the binding, the binding passes binding.root to RecyclerView.ViewHolder(binding.root)

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CardViewHolder {     val binding = CardBinding.inflate(LayoutInflater.from(parent.context), parent, false)     return CardViewHolder(binding) } 

Then access anywhere with:

holder.binding.title 
like image 40
A1m Avatar answered Oct 05 '22 23:10

A1m