How to use ViewBinding in a RecyclerView.Adapter?

前端 未结 7 2046
小鲜肉
小鲜肉 2021-02-05 01:59

Can I use ViewBindings to replace findViewById in this typical RecyclerView.Adapter initialization code? I can\'t set a binding val in the

相关标签:
7条回答
  • 2021-02-05 02:27

    If you're ok with reflection, I have a much easier way to do this. Just call ViewGroup.toBinding() then you can get the binding object you want. But since we're talk about reflection, remember you have to modify your proguard-rule to make it work even for 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
    }
    

    I put all this into an open source project you can take a look as well. Not only for Adapter usage but also include Activity and Fragment. And do let me know if you have any comment. Thanks.

    https://github.com/Jintin/BindingExtension

    0 讨论(0)
  • 2021-02-05 02:28

    I wrote a simple and reusable one:

    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"
            }
        }
    
    }
    
    0 讨论(0)
  • 2021-02-05 02:29

    just pass your model calss into xml and set these data into xml this code look fine and add a method where you add these data into binding like you don,t need to fine the id for this

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.setData(listData[position])
    
    }
    
    
    fun setData(model: ListData) {
            with(binding) {
                data = model
                executePendingBindings()
            }
        }
    
    0 讨论(0)
  • 2021-02-05 02:30

    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.

    0 讨论(0)
  • 2021-02-05 02:30

    You may use data binding like this.

    class CardListAdapter(
            private val mActivity: FragmentActivity?
        ) :
            RecyclerView.Adapter<RecyclerView.ViewHolder>() {
             private var mCustomLayoutBinding: CustomLayoutBinding? = null
    
              inner class MyViewHolder(val mBinding: CustomLayoutBinding) :
                RecyclerView.ViewHolder(mBinding.getRoot())
         override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
                if (layoutInflater == null)
                    layoutInflater = LayoutInflater.from(parent.context)
    
                var viewHolder: RecyclerView.ViewHolder? = null
                val inflater = LayoutInflater.from(parent.context)
    
           viewHolder = getViewHolder(parent, inflater)
                     return viewHolder!!
                }
                private fun getViewHolder(
                parent: ViewGroup,
                inflater: LayoutInflater
            ): RecyclerView.ViewHolder {
                mCustomLayoutBinding =
                    DataBindingUtil.inflate(inflater, R.layout.custom_layout, parent, false)
                return MyViewHolder(this!!.mAssistanceLogCustomLayoutBinding!!)
            }
              override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
                val taskModal = mArrayList.get(position)
                 holder.mBinding.txtTitle.setText(taskModal.title)
                  }
                  override fun getItemCount(): Int {
                return assistanceArrayList.size
            }
    
            override fun getItemId(position: Int): Long {
                return position.toLong()
            }
    
            override fun getItemViewType(position: Int): Int {
                return position
            }
            }
    
    0 讨论(0)
  • 2021-02-05 02:39

    You may use view-binding like this :

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

    Here is 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>
    
    0 讨论(0)
提交回复
热议问题