[英]How to use SharedPreferences in RecyclerView.Adapter in Kotlin?
[英]How to use ViewBinding in a RecyclerView.Adapter?
我可以在這個典型的RecyclerView.Adapter
初始化代碼中使用 ViewBindings 替換findViewById
嗎? 我無法在 object 中設置binding
值,因為每個單元格的 ViewHolder 都不同。
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)
// ...
}
您需要做的是將生成的綁定類對象傳遞給持有者類構造函數。 在下面的示例中,我有RecyclerView
項目的row_payment
XML 文件,生成的類是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
}
}
}
此外,請確保通過訪問傳遞的綁定類對象將根視圖傳遞給 Viewholder 的父類,如RecyclerView.ViewHolder(itemBinding.root)
。
我寫了一個簡單且可重用的:
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"
}
}
}
將binding
附加到 ViewHolder 而不是 View
class CardViewHolder(val binding: CardBinding) : RecyclerView.ViewHolder(binding.root)
你傳遞綁定,綁定將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)
}
然后通過以下方式訪問任何地方:
holder.binding.title
您可以像這樣使用視圖綁定:
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
}
}
這是 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>
如果你對反射沒意見,我有一個更簡單的方法來做到這一點。 只需調用 ViewGroup.toBinding() 即可獲得所需的綁定對象。 但是既然我們在談論反射,請記住您必須修改您的 proguard-rule 以使其即使對 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
}
我把所有這些都放到了一個開源項目中,你也可以看看。 不僅用於 Adapter 使用,還包括 Activity 和 Fragment。 如果您有任何意見,請告訴我。 謝謝。
只需將您的模型 calss 傳遞到 xml 並將這些數據設置為 xml 這段代碼看起來不錯,並添加一個方法,將這些數據添加到綁定中,就像您不需要的那樣,不需要為此調整 id
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.setData(listData[position])
}
fun setData(model: ListData) {
with(binding) {
data = model
executePendingBindings()
}
}
您可以像這樣使用數據綁定。
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
}
}
我采用了 Alan W. 所做的並將泛型添加到其中。
class ViewBindingVH <VB: ViewBinding> constructor(val binding: VB) :
RecyclerView.ViewHolder(binding.root) {
companion object {
inline fun <VB: ViewBinding> create(
parent: ViewGroup,
crossinline block: (inflater: LayoutInflater, container: ViewGroup, attach: Boolean) -> VB
) = ViewBindingVH<VB>(block(LayoutInflater.from(parent.context), parent, false))
}}
實現非常簡單,您可以避免對適配器類進行強制轉換:
class PlayerViewHolder : ListAdapter<Rate, ViewBindingVH<ChartItemBinding>>(RateDiff) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewBindingVH<ChartItemBinding> =
ViewBindingVH.create(parent, ChartItemBinding::inflate)
override fun onBindViewHolder(holder: ViewBindingVH<ChartItemBinding>, position: Int) {
val item = currentList[position]
holder.binding.apply {
}
}}
object RateDiff: DiffUtil.ItemCallback<Rate>(){
override fun areContentsTheSame(oldItem: Rate, newItem: Rate): Boolean {
return oldItem == newItem
}
override fun areItemsTheSame(oldItem: Rate, newItem: Rate): Boolean {
return oldItem == newItem
}}
abstract class BaseRecyclerViewAdapter<T : Any, VB : ViewBinding>(
private var dataList: ArrayList<T>)
: RecyclerView.Adapter<BaseRecyclerViewAdapter.MyViewViewHolder<VB>>()
{
protected var bindingInterface: GenericSimpleRecyclerBindingInterface<T, VB>? = null
class MyViewViewHolder<VB : ViewBinding>(val viewBinding: VB) :
RecyclerView.ViewHolder(viewBinding.root) {
fun <T : Any> bind(
item: T,
position: Int,
bindingInterface: GenericSimpleRecyclerBindingInterface<T, VB>
) = bindingInterface.bindData(item, position, viewBinding)
}
@SuppressLint("NotifyDataSetChanged")
fun updateList(list: ArrayList<T>) {
dataList.clear()
dataList.addAll(list)
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int):MyViewViewHolder<VB> {
val view = inflateView(LayoutInflater.from(parent.context))
return MyViewViewHolder(view)
}
override fun onBindViewHolder(holder: MyViewViewHolder<VB>, position: Int) {
val item = dataList[position]
holder.bind(item, position, bindingInterface!!)
}
override fun getItemCount(): Int = dataList.size
abstract fun inflateView(inflater: LayoutInflater): VB
}
interface GenericSimpleRecyclerBindingInterface<T : Any, VB : ViewBinding> {
fun bindData(item: T, position: Int, viewBinding: VB)
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.