kotlin 带有ViewBinding的通用Recycler视图适配器

7gyucuyw  于 2022-12-30  发布在  Kotlin
关注(0)|答案(1)|浏览(240)
    • bounty将在6天后过期**。回答此问题可获得+50声望奖励。Sorry希望引起更多人对此问题的关注:赏金猎人快乐,伙计们,让我们听听你的建议。

我正在尝试实现一个通用的RV适配器,主要是受THIS COMMENT的启发:
代码:

class RVAdapter <T: Any, VB: ViewBinding>(
  private var dataSet: List<T>,
  private val bindingInterface: RVBinding<T, VB>
  ) : ListAdapter<T, RVAdapter<T, VB>.RVHolder>(DiffCallback<T>()) {

  inner class RVHolder(private val binding: ViewBinding): RecyclerView.ViewHolder(binding.root) {
    fun<T: Any, VB: ViewBinding> bind(item: T, bindingInterface: RVBinding<T, VB>) {
      bindingInterface.bind(item, (binding as VB)) //3: unchecked cast
    }
  }

  override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RVHolder {
    val binding = (VB as ViewBinding).inflate() //1: how do you inflate from generic VB?

    return RVHolder(binding)
  }

  override fun onBindViewHolder(holder: RVHolder, position: Int) {
    holder.bind(getItem(position), bindingInterface)
  }

  override fun getItemCount() = dataSet.size
}

private class DiffCallback<T: Any>: DiffUtil.ItemCallback<T>() {
  //2: how do you implement the following two methods?

  override fun areItemsTheSame(oldItem: T, newItem: T): Boolean {
    TODO("Not yet implemented")
  }

  override fun areContentsTheSame(oldItem: T, newItem: T): Boolean {
    return oldItem == newItem
  }
}

interface RVBinding<T: Any, VB: ViewBinding> {
  fun bind(item: T, binding: VB)
}

我面临两个主要问题:
1.如何在onCreateViewHolder()中扩展绑定?通常,我使用SpecificBinding.inflate(),但这似乎不适用于通用视图绑定。
1.我如何以通用的方式实现DiffUtil部分?当然,我可以比较old.toString == new.toString,但那不是通用的。而且oldItem == newItem没有实现equals()
那么,我如何解决这些问题,使适配器尽可能通用呢?任何其他建议都是受欢迎的。

a11xaf1n

a11xaf1n1#

例如,您可以使用下面的通用结构。

abstract class AbstractViewBindingAdapter<T, VH : RecyclerView.ViewHolder, VB : ViewBinding>(
        private val viewHolder: (binding: VB) -> VH,
        private val bindingInflater: (LayoutInflater, ViewGroup, Boolean) -> VB,
        areItemsTheSameCallback: (old: T, new: T) -> Boolean? = { _, _ -> null },
        areContentsTheSameCallback: (old: T, new: T) -> Boolean? = { _, _ -> null },
        private val onCreateBinding: (holder: VH) -> Unit = {}

) :
        ListAdapter<T, VH>(GenericDiffUtil(areItemsTheSameCallback, areContentsTheSameCallback)) {
    abstract fun bindItems(item: T, holder: VH, position: Int, itemCount: Int)

    var forItemClickListener: ((position: Int, item: T, view: View) -> Unit)? = null
    var onLongClickListener: ((position: Int, item: T, view: View) -> Unit)? = null

    override fun onBindViewHolder(holder: VH, position: Int) {
        val item: T = getItem(holder.bindingAdapterPosition)
        bindItems(item, holder, position, itemCount)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH {
        val binding = bindingInflater.invoke(LayoutInflater.from(parent.context), parent, false)
        val holder = setViewHolder(binding)
        onCreateBinding(holder)

        holder.itemView.setOnClickListenerCooldown {
            if (holder.bindingAdapterPosition != RecyclerView.NO_POSITION)
                forItemClickListener?.invoke(holder.bindingAdapterPosition, getItem(holder.bindingAdapterPosition), it)
        }
        holder.itemView.setOnLongClickListener {
            if (holder.bindingAdapterPosition != RecyclerView.NO_POSITION)
                onLongClickListener?.invoke(holder.bindingAdapterPosition, getItem(holder.bindingAdapterPosition), it)
            true
        }
        return holder
    }

    @Suppress("UNCHECKED_CAST")
    private fun setViewHolder(binding: ViewBinding): VH = viewHolder(binding as VB)
}

GenericDiffUtil.kt

class GenericDiffUtil<T>(private val areItemsTheSameCallback: (old: T, new: T) -> Boolean?,
                         private val areContentsTheSameCallback: (old: T, new: T) -> Boolean?) : DiffUtil.ItemCallback<T>() {

    override fun areItemsTheSame(oldItem: T, newItem: T): Boolean = areItemsTheSameCallback(oldItem, newItem) ?: newItem == oldItem

    @SuppressLint("DiffUtilEquals")
    override fun areContentsTheSame(oldItem: T, newItem: T): Boolean = areContentsTheSameCallback(oldItem, newItem) ?: newItem == oldItem

}

fun <T> diffUtilDSL(areItemsTheSameCallback: (old: T, new: T) -> Boolean? = { _, _ -> null },
                    areContentsTheSameCallback: (old: T, new: T) -> Boolean? = { _, _ -> null }) = GenericDiffUtil(areItemsTheSameCallback, areContentsTheSameCallback)

相关问题