如何在 RecyclerView.Adapter 中使用 ViewBinding?

A1m*_*A1m 65 android android-viewbinding

我可以使用 ViewBindings 来替换findViewById这个典型的RecyclerView.Adapter初始化代码吗?我无法binding在对象中设置val,因为每个单元格的 ViewHolders 都不同。

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)
        // ...
    }
Run Code Online (Sandbox Code Playgroud)

Som*_*mar 136

您需要做的是将生成的绑定类对象传递给持有者类构造函数。在下面的示例中,我有项目的row_paymentXML 文件,RecyclerView生成的类是RowPaymentBinding这样的

    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
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

此外,请确保RecyclerView.ViewHolder(itemBinding.root)通过访问传递的绑定类对象将根视图传递给 Viewholder 的父类。

  • 很干净。谢谢。对绑定函数的改进是:`fun bind( paymentBean: PaymentBean) = with(itemBinding) { tvPaymentInvoiceNumber.text = paymentBean.invoiceNumber tvPaymentAmount.text = paymentBean.totalAmount }` ...以避免重复写入`itemBinding` 。 (4认同)
  • 或者,为了避免重复“itemBinding”,您可以使用“itemBinding.apply { ... }” (2认同)
  • @robsn是的,我们可以做到这一点..但这不是这个答案的目的,我想让初学者变得容易,这就是我没有使用范围函数的原因。 (2认同)
  • 为什么在安装 Recyclerview 而不是 paymentHolder paymentWhatever 时不能将名称保留为默认值 (2认同)

Ala*_*ang 7

我写了一个简单且可重用的:

class ViewBindingVH constructor(val binding: ViewBinding) :
    RecyclerView.ViewHolder(binding.root) {
    
    companion object {
        inline fun create(
            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.create(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"
        }
    }

}
Run Code Online (Sandbox Code Playgroud)


Sat*_*dde 6

您可以像这样使用视图绑定:

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
}

}
Run Code Online (Sandbox Code Playgroud)

这是 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>
Run Code Online (Sandbox Code Playgroud)


A1m*_*A1m 5

附加binding到 ViewHolder 而不是 View

class CardViewHolder(val binding: CardBinding) : RecyclerView.ViewHolder(binding.root)
Run Code Online (Sandbox Code Playgroud)

你传递绑定,绑定传递binding.rootRecyclerView.ViewHolder(binding.root)

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

然后通过以下方式访问任何地方:

holder.binding.title
Run Code Online (Sandbox Code Playgroud)


Jin*_*tin 5

如果你同意反思,我有一个更简单的方法来做到这一点。只需调用 ViewGroup.toBinding() 即可获取所需的绑定对象。但既然我们谈论的是反射,请记住你必须修改你的 proguard 规则以使其即使对于 proguard 也能工作。

// inside adapter
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
    return MainViewHolder(parent.toBinding())
}

// ViewHolder
class MainViewHolder(private val binding: AdapterMainBinding) :
    RecyclerView.ViewHolder(binding.root) {

    fun bind(data: String) {
        binding.name.text = data
    }
}

// The magic reflection can reused everywhere.
inline fun <reified V : ViewBinding> ViewGroup.toBinding(): V {
    return V::class.java.getMethod(
        "inflate",
        LayoutInflater::class.java,
        ViewGroup::class.java,
        Boolean::class.java
    ).invoke(null, LayoutInflater.from(context), this, false) as V
}
Run Code Online (Sandbox Code Playgroud)

我把所有这些都放到了一个开源项目中,你也可以看看。不仅适用于Adapter的使用,还包括Activity和Fragment的使用。如果您有任何意见,请告诉我。谢谢。

https://github.com/Jintin/BindingExtension