123 votes

Comment utiliser ViewBinding dans un RecyclerView.Adapter ?

Puis-je utiliser ViewBindings pour remplacer findViewById dans ce code d'initialisation RecyclerView.Adapter Je ne peux pas définir une valeur binding dans l'objet car les ViewHolders sont différents par cellule.

 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)
        // ...
    }

235voto

Somesh Kumar Points 2343

Ce que vous devez faire est de transmettre l'objet de classe de liaison généré au constructeur de classe titulaire. Dans exemple ci - dessous, je row_payment fichier XML pour RecyclerView article et la classe générée est RowPaymentBinding alors comme celui - ci

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

Assurez-vous également de transmettre la vue racine à la classe parent de Viewholder comme ceci RecyclerView.ViewHolder(itemBinding.root) en accédant à l'objet de classe de liaison transmis.

37voto

A1m Points 634

Attachez le binding au ViewHolder au lieu du View

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

Vous passez la reliure, la reliure passe binding.root à 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)
    }

Accédez ensuite n'importe où avec :

     holder.binding.title

11voto

Alan W. Points 3921

J'en ai écrit un simple et réutilisable :

 class ViewBindingVH private constructor(val binding: ViewBinding) :
    RecyclerView.ViewHolder(binding.root) {
    
    companion object {
        inline fun createVH(
            parent: ViewGroup,
            crossinline block: (inflater: LayoutInflater, container: ViewGroup, attach: Boolean) -> ViewBinding
        ) = ViewBindingVH(block(LayoutInflater.from(parent.context), parent, false))
    }
}


class CardAdapter : RecyclerView.Adapter<ViewBindingVH>() {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewBindingVH {
        return ViewBindingVH.createVH(parent, CardBinding::inflate)
    }

    override fun onBindViewHolder(holder: ViewBindingVH, position: Int) {
        (holder.binding as CardBinding).apply {
            //bind model to view
            title.text = "some text"
            descripiton.text = "some text"
        }
    }

}

6voto

Sathish Gadde Points 434

Vous pouvez utiliser la liaison de vue comme ceci :

 package com.example.kotlinprogramming.adapter

import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.kotlinprogramming.data.HobbiesData
import com.example.kotlinprogramming.databinding.ItemHobbieBinding

class HobbiesAdapter(var context: Context, var hobbiesList: List<HobbiesData>) :
RecyclerView.Adapter<HobbiesAdapter.HobbiesViewHolder>() {


override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HobbiesViewHolder {
    val view = ItemHobbieBinding.inflate(LayoutInflater.from(context) , parent,false)
    return HobbiesViewHolder(view)
}

override fun onBindViewHolder(holder: HobbiesViewHolder, position: Int) {
    val hobbie = hobbiesList.get(position)
    holder.viewBinding.tvHobbie.text = hobbie.title
}

inner class HobbiesViewHolder(var viewBinding: ItemHobbieBinding) : RecyclerView.ViewHolder(viewBinding.root) {
}

override fun getItemCount(): Int {
    return hobbiesList.size
}

}

Voici item_hobbies.xml

 <?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView 
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_margin="12dp"
android:layout_height="wrap_content"
>
<TextView
    android:id="@+id/tvHobbie"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="8dp"
    android:gravity="center"
    android:textSize="30sp"
    tools:text="Hobbie1"
    />
</androidx.cardview.widget.CardView>

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X