【问题标题】:DataBinding: How to create Recyclerview with multiple ViewHolder (multiple layout) using generics in KotlinDataBinding:如何使用 Kotlin 中的泛型创建具有多个 ViewHolder(多个布局)的 Recyclerview
【发布时间】:2021-06-19 22:23:33
【问题描述】:

我有下面的代码,我在具有多个 ViewHolders 的 RecyclerView 中使用泛型,我正在尝试使用 DataBinding 升级此代码,我正在寻找具有多个 ViewHolders 的 RecyclerView 并在其中使用 DataBinding。

class JumbledWordAdapter(
var items: List<JumbledWord>
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

companion object {
    const val TYPE_PLACE_HOLDER = 0
    const val TYPE_ANSWER = 1
    const val INVALID = -1
}

var selectedItemPos = INVALID

override fun getItemViewType(position: Int) = (items[position].currentType)//choose layout type

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
    return when (viewType) {
        TYPE_PLACE_HOLDER -> {
            PlaceHolderViewHolder(
                LayoutInflater.from(parent.context)
                    .inflate(R.layout.lyt_jumbled_word_place_holder_item, parent, false)
            )
        }
        TYPE_ANSWER -> {
            AnswerViewHolder(
                LayoutInflater.from(parent.context)
                    .inflate(R.layout.lyt_jumbled_word_answer_item, parent, false)
            )
        }
        else -> throw IllegalArgumentException("Invalid view type")
    }
}

override fun getItemCount(): Int = items.size

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
    when (holder) {
        is PlaceHolderViewHolder -> holder.bind(position)
        is AnswerViewHolder -> holder.bind(position)
    }
}

inner class PlaceHolderViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
    private val cardParent: MaterialCardView = view.findViewById(R.id.cardParent)
    fun bind(position: Int) {
        cardParent.isSelected = items[position].isSelected
        cardParent.setOnClickListener {
           //some code.
        }
    }
}

inner class AnswerViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
    private val cardParent: MaterialCardView = view.findViewById(R.id.cardParent)
    private val tvLetter: TextView = view.findViewById(R.id.tvLetter)
    fun bind(position: Int) {
        tvLetter.text = items[position].answer
        cardParent.setOnClickListener {
           //some code.
        }
    }
 }
}

需要在这个适配器类中实现Databinding。

【问题讨论】:

    标签: android performance android-layout kotlin generics


    【解决方案1】:

    我认为 DataBinding 应该在 ViewHolder 中隔离,因为将值绑定到视图不是 Adapter 的责任。

    所以我写了这个:

    class JumbledWordAdapter(
        val items: List<ItemListFragment.JumbledWord>
    ) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
    
        companion object {
            const val TYPE_PLACE_HOLDER = 0
            const val TYPE_ANSWER = 1
            const val INVALID = -1
        }
    
        var selectedItemPos = INVALID
    
        override fun getItemViewType(position: Int) = (items[position].currentType)//choose layout type
    
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
            return when (viewType) {
                TYPE_PLACE_HOLDER -> PlaceHolderViewHolder(parent)
                TYPE_ANSWER -> AnswerViewHolder(parent)
                else -> throw IllegalArgumentException("Invalid view type")
            }
        }
    
        override fun getItemCount(): Int = items.size
    
        override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
            when (holder) {
                is PlaceHolderViewHolder -> holder.bind(position)
                is AnswerViewHolder -> holder.bind(position)
            }
        }
    
        inner class PlaceHolderViewHolder private constructor(
            val binding: LytJumbledWordPlaceHolderItemBinding
        ) : RecyclerView.ViewHolder(binding.root) {
    
            constructor(parent: ViewGroup) : this(
                LytJumbledWordPlaceHolderItemBinding.inflate(
                    LayoutInflater.from(parent.context),
                    parent,
                    false
                )
            )
    
            init {
                // set click listeners at view-holder initialize time
                binding.cardParent.setOnClickListener {
                    if (adapterPosition != RecyclerView.NO_POSITION) {
                        //some code.    
                    }
                }
            }
    
            fun bind(position: Int) {
                binding.cardParent.isSelected = items[position].isSelected
            }
        }
    
        inner class AnswerViewHolder private constructor(
            val binding: LytJumbledWordAnswerItemBinding
        ) : RecyclerView.ViewHolder(binding.root) {
    
            constructor(parent: ViewGroup) : this(
                LytJumbledWordAnswerItemBinding.inflate(
                    LayoutInflater.from(parent.context),
                    parent,
                    false
                )
            )
    
            init {
                // set click listeners at view-holder initialize time
                binding.cardParent.setOnClickListener {
                    if (adapterPosition != RecyclerView.NO_POSITION) {
                        //some code.    
                    }
                }
            }
    
            fun bind(position: Int) {
                binding.tvLetter.text = items[position].answer
            }
        }
    }
    

    PS:我们还应该在viewholder初始化时间设置clickListeners。 (不在绑定时间内)

    【讨论】:

    • adapterPosition 已弃用。我可以使用 getBindingAdapterPosition() 吗?
    • @Alfin 我正在使用最新的稳定版本的 recyclerview (1.1.0)。如果您使用的是不稳定版本,是的。你可以改用getBindingAdapterPosition()。
    猜你喜欢
    • 1970-01-01
    • 2021-01-17
    • 2018-06-06
    • 1970-01-01
    • 2014-04-07
    • 1970-01-01
    • 2023-03-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多