You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在RecyclerView中点击切换Item背景色且不使用notifyDataSetChanged

最佳解决方案:精准刷新选中/取消选中的Item

你当前用notifyDataSetChanged()会强制刷新整个列表,完全浪费了RecyclerView的局部刷新能力。正确的做法是只刷新之前选中的Item和新选中的Item,具体修改步骤如下:

1. 修改点击事件的刷新逻辑

在ViewHolder的点击监听里,先记录旧的选中位置,更新新的选中位置后,分别对两个位置调用notifyItemChanged():

binding.root.setOnClickListener {
    val oldSelected = selectedItem
    selectedItem = adapterPosition
    // 刷新旧选中项(如果存在)
    if (oldSelected != -1) {
        notifyItemChanged(oldSelected)
    }
    // 刷新新选中项
    notifyItemChanged(selectedItem)
    onItemClickListener?.invoke(item)
}

2. 移除不必要的setIsRecyclable(false)

这行代码会禁用RecyclerView的View复用机制,严重影响性能,直接删除holder.setIsRecyclable(false)即可——只要你的bind()方法能正确根据selectedItem状态设置UI,复用完全没问题。

3. 优化DiffUtils的判断逻辑(可选但推荐)

你当前的NotesDiffUtils里用===引用判断,对于数据类来说,应该用内容相等判断更合理,比如如果Data是数据类,可以改成:

override fun areItemsTheSame(oldPos: Int, newPos: Int): Boolean {
    return oldItem[oldPos].id == newItem[newPos].id // 用唯一标识判断是否是同一个Item
}

override fun areContentsTheSame(oldPos: Int, newPos: Int): Boolean {
    return oldItem[oldPos] == newItem[newPos] // 数据类自动生成equals,判断内容是否一致
}

修改后的核心代码片段

inner class ViewHolder : RecyclerView.ViewHolder(binding.root) {

    @SuppressLint("SetTextI18n")
    fun bind(item: Data) {
        binding.apply {
            selectedTxt.text = item.description
            // 点击事件处理
            binding.root.setOnClickListener {
                val oldSelected = selectedItem
                selectedItem = adapterPosition
                if (oldSelected != -1) {
                    notifyItemChanged(oldSelected)
                }
                notifyItemChanged(selectedItem)
                onItemClickListener?.invoke(item)
            }
            // 根据选中状态设置UI
            val isSelected = selectedItem == adapterPosition
            binding.selectedImg.setImageResource(
                if (isSelected) R.drawable.bg_circle_selected else R.drawable.bg_circle_un_selected
            )
        }
    }
}

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    holder.bind(moviesList[position])
    // 移除禁用复用的代码
}

方案优势

  • 性能更优:最多仅刷新2个Item,避免全量刷新带来的性能损耗
  • 符合设计理念:充分利用RecyclerView的局部刷新机制,保留View复用特性
  • 逻辑清晰:明确控制需要更新的位置,代码可读性更强

内容的提问来源于stack exchange,提问作者Jojo Drink

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 20:35:00