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

RecyclerView条目状态留存问题求助:答案状态与颜色无法保持

解决RecyclerView条目复用导致状态丢失问题

问题背景

实现一个展示题目的RecyclerView,每个条目包含问题TextView和5个对应答案的CheckBox。点击correctButton会将正确答案标绿、错误答案标红;点击retryButton重置状态。但条目复用时,已交互过的条目会被重置为默认状态(复选框未勾选、答案无颜色标记),无法保留之前的交互状态。

问题原因

  1. ViewHolder复用机制:RecyclerView会复用已创建的ViewHolder,每次滚动触发onBindViewHolder时,原代码强制将所有CheckBox设为未勾选、文本颜色设为黑色,直接覆盖了之前的交互状态。
  2. 状态未持久化:原Question类仅存储题目和答案数据,未保存用户的交互状态(如是否已查看答案、用户勾选的选项),导致复用条目时无法恢复之前的操作状态。

解决方案

1. 修改数据模型,添加状态字段

更新Question类,增加用于保存交互状态的字段,让每个问题的状态与数据绑定:

data class Question(
    val question: String?,
    val answers: List<String>,
    val correctAnswers: List<Boolean>,
    // 标记当前题目是否已展示过答案
    var isAnswerShown: Boolean = false,
    // 保存用户勾选的选项状态(对应A-E共5个选项)
    var userSelectedOptions: MutableList<Boolean> = MutableList(5) { false }
)

2. 重构适配器的onBindViewHolder方法

不再强制设置默认UI状态,而是从Question对象中读取已保存的状态并恢复UI:

class QuestionAdapter : RecyclerView.Adapter<QuestionAdapter.QuestionViewHolder>() {
    var allQuestions = ArrayList<Question>()

    inner class QuestionViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val question: TextView = itemView.findViewById(R.id.tv_question)
        val answerA: CheckBox = itemView.findViewById(R.id.answerA)
        val answerB: CheckBox = itemView.findViewById(R.id.answerB)
        val answerC: CheckBox = itemView.findViewById(R.id.answerC)
        val answerD: CheckBox = itemView.findViewById(R.id.answerD)
        val answerE: CheckBox = itemView.findViewById(R.id.answerE)

        val optionError: TextView = itemView.findViewById(R.id.optionError)
        val correctButton: Button = itemView.findViewById(R.id.correctButton)
        val retryButton: Button = itemView.findViewById(R.id.retryButton)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): QuestionViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.question_item, parent, false)
        return QuestionViewHolder(view)
    }

    override fun getItemCount(): Int = allQuestions.size

    override fun onBindViewHolder(holder: QuestionViewHolder, position: Int) {
        val currentQuestion = allQuestions[position]
        val answersCheckboxList = arrayOf(holder.answerA, holder.answerB, holder.answerC, holder.answerD, holder.answerE)

        holder.apply {
            // 初始化问题文本
            question.text = currentQuestion.question
            // 默认隐藏错误提示
            optionError.visibility = View.GONE

            // 遍历恢复每个CheckBox的状态
            for (i in answersCheckboxList.indices) {
                val checkBox = answersCheckboxList[i]
                checkBox.text = currentQuestion.answers[i]
                
                // 恢复用户之前的勾选状态
                checkBox.isChecked = currentQuestion.userSelectedOptions[i]
                
                // 根据是否展示答案设置文本颜色
                checkBox.setTextColor(
                    if (currentQuestion.isAnswerShown) {
                        if (currentQuestion.correctAnswers[i]) Color.GREEN else Color.RED
                    } else {
                        Color.BLACK
                    }
                )

                // 监听勾选变化,实时保存到数据模型
                checkBox.setOnCheckedChangeListener { _, isChecked ->
                    currentQuestion.userSelectedOptions[i] = isChecked
                }
            }

            correctButton.setOnClickListener {
                val hasSelected = currentQuestion.userSelectedOptions.any { it }
                if (hasSelected) {
                    // 标记已展示答案,触发当前条目UI更新
                    currentQuestion.isAnswerShown = true
                    notifyItemChanged(position)
                } else {
                    // 未选择任何选项时显示错误提示
                    optionError.visibility = View.VISIBLE
                }
            }

            retryButton.setOnClickListener {
                // 重置当前题目的所有状态,触发UI更新
                currentQuestion.isAnswerShown = false
                currentQuestion.userSelectedOptions.fill(false)
                notifyItemChanged(position)
            }
        }
    }
}

关键说明

  • 状态与数据绑定:将用户的交互状态(勾选选项、是否展示答案)存储在Question对象中,确保每个条目的状态不受ViewHolder复用影响。
  • UI状态按需恢复:在onBindViewHolder中根据数据模型的状态恢复UI,而非强制设置默认值。
  • 局部更新优化:使用notifyItemChanged(position)触发单个条目的UI更新,避免全量刷新影响性能。

内容的提问来源于stack exchange,提问作者Elijah Banda

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 00:23:20