如何给RecyclerView的ViewHolder添加Binding以获取tvTodoTitle和cbDone
为RecyclerView的ViewHolder添加ViewBinding获取控件的解决方案
一、核心实现步骤(使用ViewBinding)
首先确保项目已启用ViewBinding,在模块级build.gradle(或build.gradle.kts)中添加配置:
android { buildFeatures { viewBinding true } }
接下来修改TodoAdapter代码,将ViewBinding集成到ViewHolder中:
- 重构ViewHolder类
将原本接收View的ViewHolder,替换为接收对应item布局的自动生成Binding类(此处为ItemTodoBinding,由item_todo.xml自动生成):
class TodoViewHolder(val binding: ItemTodoBinding) : RecyclerView.ViewHolder(binding.root)
- 修改onCreateViewHolder方法
不再直接inflate布局View,而是通过Binding类的inflate方法创建实例并传入ViewHolder:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TodoViewHolder { val binding = ItemTodoBinding.inflate(LayoutInflater.from(parent.context), parent, false) return TodoViewHolder(binding) }
- 优化onBindViewHolder逻辑
通过holder.binding直接访问布局内控件(tvTodoTitle和cbDone),无需再通过itemView查找:
override fun onBindViewHolder(holder: TodoViewHolder, position: Int) { val curTodo = todos[position] with(holder.binding) { // 修正原代码笔误:etTodoTitle应为tvTodoTitle,且需设置text属性 tvTodoTitle.text = curTodo.title cbDone.isChecked = curTodo.isChecked toggleStrikeThrough(tvTodoTitle, curTodo.isChecked) cbDone.setOnCheckedChangeListener { _, isChecked -> toggleStrikeThrough(tvTodoTitle, isChecked) // 修正原逻辑错误:直接赋值为当前选中状态即可 curTodo.isChecked = isChecked } } }
二、完整修改后的TodoAdapter代码
package com.example.todoit import android.graphics.Paint.STRIKE_THRU_TEXT_FLAG import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import com.example.todoit.data.Todo import com.example.todoit.databinding.ItemTodoBinding class TodoAdapter( private val todos: MutableList<Todo>, ) : RecyclerView.Adapter<TodoAdapter.TodoViewHolder>() { class TodoViewHolder(val binding: ItemTodoBinding) : RecyclerView.ViewHolder(binding.root) override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TodoViewHolder { val binding = ItemTodoBinding.inflate(LayoutInflater.from(parent.context), parent, false) return TodoViewHolder(binding) } fun addTodo(todo: Todo) { todos.add(todo) notifyItemInserted(todos.size - 1) } fun deleteDoneTodos() { todos.removeAll { todo -> todo.isChecked } notifyDataSetChanged() } private fun toggleStrikeThrough(tvTodoTitle: androidx.appcompat.widget.AppCompatTextView, isChecked: Boolean) { if (isChecked) { tvTodoTitle.paintFlags = tvTodoTitle.paintFlags or STRIKE_THRU_TEXT_FLAG } else { tvTodoTitle.paintFlags = tvTodoTitle.paintFlags and STRIKE_THRU_TEXT_FLAG.inv() } } override fun onBindViewHolder(holder: TodoViewHolder, position: Int) { val curTodo = todos[position] with(holder.binding) { tvTodoTitle.text = curTodo.title cbDone.isChecked = curTodo.isChecked toggleStrikeThrough(tvTodoTitle, curTodo.isChecked) cbDone.setOnCheckedChangeListener { _, isChecked -> toggleStrikeThrough(tvTodoTitle, isChecked) curTodo.isChecked = isChecked } } } override fun getItemCount(): Int { return todos.size } }
三、替代方案(不使用ViewBinding)
若暂时不想使用ViewBinding,可在ViewHolder中提前通过findViewById缓存控件,避免重复查找:
class TodoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { val tvTodoTitle: TextView = itemView.findViewById(R.id.tvTodoTitle) val cbDone: CheckBox = itemView.findViewById(R.id.cbDone) } // 在onBindViewHolder中直接调用缓存的控件 override fun onBindViewHolder(holder: TodoViewHolder, position: Int) { val curTodo = todos[position] holder.tvTodoTitle.text = curTodo.title holder.cbDone.isChecked = curTodo.isChecked // 后续逻辑同上 }
额外修复点(原代码中的小问题)
- MainActivity中
binding.etTodoTitle.toString()需改为binding.etTodoTitle.text.toString(),否则获取的是TextView对象字符串而非输入文本 - MainActivity中
todoDB未初始化,需在onCreate中添加todoDB = TodoDataBase.getInstance(this)(假设数据库类有单例实现) - TodoAdapter中lambda表达式语法错误:
todo -和isChecked -需改为todo ->和isChecked ->
内容的提问来源于stack exchange,提问作者Clivityy
相关产品推荐
相关产品推荐

