首页 > 解决方案 > 在基于测验的应用程序中具有嵌套 setOnClickListener 的 RecyclerView

问题描述

我对基于测验的应用程序的基本功能的实现有疑问。简而言之,我在 an 中有“问题”和“答案” ArrayList<Question>(每个Question都有自己的ArrayList<Answer>,在本示例中为3 个),用于RecyclerView在 MVVM 管理的片段中填充 a 的适配器。

这是我的onBindViewHolder功能:

  ...
  
  override fun onBindViewHolder(holder: MyViewHolder, position: Int) {        
 
  ...

    val curQuest = myDataset[position]    
    val shuffledAnswers = curQuest.answers


    holder.ans1.text = shuffledAnswers[0].answer_text
    holder.ans1.setOnClickListener {
        it.background = ContextCompat.getDrawable(parentFragment.requireContext(),R.drawable.selected_ans_quiz)
        holder.ans2.background = ContextCompat.getDrawable(parentFragment.requireContext(),R.drawable.default_ans_quiz)
        holder.ans3.background = ContextCompat.getDrawable(parentFragment.requireContext(),R.drawable.default_ans_quiz)
    }

    holder.ans2.text = shuffledAnswers[1].answer_text
    holder.ans2.setOnClickListener {
        it.background = ContextCompat.getDrawable(parentFragment.requireContext(),R.drawable.selected_ans_quiz)
        holder.ans1.background = ContextCompat.getDrawable(parentFragment.requireContext(),R.drawable.default_ans_quiz)
        holder.ans3.background = ContextCompat.getDrawable(parentFragment.requireContext(),R.drawable.default_ans_quiz)
    }

    holder.ans3.text = shuffledAnswers[2].answer_text
    holder.ans3.setOnClickListener {
        it.background = ContextCompat.getDrawable(parentFragment.requireContext(),R.drawable.selected_ans_quiz)
        holder.ans2.background = ContextCompat.getDrawable(parentFragment.requireContext(),R.drawable.default_ans_quiz)
        holder.ans1.background = ContextCompat.getDrawable(parentFragment.requireContext(),R.drawable.default_ans_quiz)
    }
 }

一切正常,但选择了答案:如果我选择第一个问题的答案 ( ),列表中的N+0元素myDataset[0]的视图也会发生变化,其中N是由RecyclerView

在加载的第 NRecyclerView元素之后,如何在不传播的情况下为每个子元素设置正确的属性?onBindViewHolder

它可以修复还是我必须改变实现方式?

编辑:我刚刚尝试了一个替代方案,但结果相同,使用界面:

QuizAdapter.kt

  ...
  
  override fun onBindViewHolder(holder: MyViewHolder, position: Int) {        
 
  ...

    val curQuest = myDataset[position]    
    val shuffledAnswers = curQuest.answers


    holder.ans1.text = shuffledAnswers[0].answer_text
    holder.ans1.setOnClickListener {
        mCallback.onClick(shuffledAnswers[0],position,it,holder.ans2,holder.ans3)
    }

    holder.ans2.text = shuffledAnswers[1].answer_text
    holder.ans2.setOnClickListener {
        mCallback.onClick(shuffledAnswers[1],position,it,holder.ans1,holder.ans3)
    }

    holder.ans3.text = shuffledAnswers[2].answer_text
    holder.ans3.setOnClickListener {
        mCallback.onClick(shuffledAnswers[2],position,it,holder.ans2,holder.ans1)
 }

 interface OnItemClickListener{
      fun onClick(answerSelected: Answer?, questPosition: Int, selectedItemView: View, firstItemView: View, secondItemView: View)
 }

QuizFragment.kt

...

        mAdapter = QuizAdapter(this)
        listQuestions.apply {
            setHasFixedSize(true)
            layoutManager = LinearLayoutManager(activity)
            adapter = mAdapter
            itemAnimator = DefaultItemAnimator()
        }
        mAdapter.setOnItemClickListener(object : QuizAdapter.OnItemClickListener{
            override fun onClick(answerSelected: Answer?,
                                 questPosition: Int,
                                 selectedItemView: View,
                                 firstItemView: View,
                                 secondItemView: View) {
                Snackbar.make(selectedItemView, "Your answer for $questPosition is ${answerSelected!!.isCorrect}.",
                        Snackbar.LENGTH_SHORT)
                        .setAction("Action", null).show()
                selectedItemView.background = ContextCompat.getDrawable(requireContext(),R.drawable.selected_ans_quiz)
                firstItemView.background = ContextCompat.getDrawable(requireContext(),R.drawable.default_ans_quiz)
                secondItemView.background = ContextCompat.getDrawable(requireContext(),R.drawable.default_ans_quiz)
                quizViewModel.chosenAnswers[questPosition] = answerSelected
            }
        })

        fab_endQuiz.setOnClickListener { view ->
            Snackbar.make(view, quizViewModel.chosenAnswers.toString(), Snackbar.LENGTH_LONG)
                    .setAction("Action", null).show()
            //parentFragment?.findNavController()?.navigate(R.id.action_quizFragment_to_nav_home)
        }

如您所见,使用 FAB,我可以测试所选答案的正确性,看起来还可以,地图充满了用户的选择,即使选择发生了变化(代表问题的地图位置已正确修改) . 但是背景颜色仍然混合在不同的位置(当前在 RecyclerView 中可见的位置加上前面的其他位置),如前所述。

标签: androidkotlinandroid-recyclerviewonclicklistenerandroid-viewholder

解决方案


如果它有用,我找到了解决方案。我向类添加了一个布尔值,Answer以便RecyclerView必须检查在 xml 中构建其列表时是否与我之前所做的混合

QuizAdapter.kt

  ...
  
  override fun onBindViewHolder(holder: MyViewHolder, position: Int) {        
 
  ...

    val curQuest = myDataset[position]    
    val shuffledAnswers = curQuest.answers


    holder.ans1.text = shuffledAnswers[0].answer_text
    if(shuffledAnswers[0].isSelected)
        holder.ans1.background = ContextCompat.getDrawable(parentFragment.requireContext(),R.drawable.selected_ans_quiz)
    else
        holder.ans1.background = ContextCompat.getDrawable(parentFragment.requireContext(),R.drawable.default_ans_quiz)
    holder.ans1.setOnClickListener {
        shuffledAnswers[0].isSelected = true
        shuffledAnswers[1].isSelected = false
        shuffledAnswers[2].isSelected = false
        mCallback.onClick(shuffledAnswers[0],position,it,holder.ans2,holder.ans3)
    }

    holder.ans2.text = shuffledAnswers[1].answer_text
    if(shuffledAnswers[1].isSelected)
        holder.ans2.background = ContextCompat.getDrawable(parentFragment.requireContext(),R.drawable.selected_ans_quiz)
    else
        holder.ans2.background = ContextCompat.getDrawable(parentFragment.requireContext(),R.drawable.default_ans_quiz)
    holder.ans2.setOnClickListener {
        shuffledAnswers[0].isSelected = false
        shuffledAnswers[1].isSelected = true
        shuffledAnswers[2].isSelected = false
        mCallback.onClick(shuffledAnswers[1],position,it,holder.ans1,holder.ans3)
    }

    holder.ans3.text = shuffledAnswers[2].answer_text
    if(shuffledAnswers[2].isSelected)
        holder.ans3.background = ContextCompat.getDrawable(parentFragment.requireContext(),R.drawable.selected_ans_quiz)
    else
        holder.ans3.background = ContextCompat.getDrawable(parentFragment.requireContext(),R.drawable.default_ans_quiz)
    holder.ans3.setOnClickListener {
        shuffledAnswers[0].isSelected = false
        shuffledAnswers[1].isSelected = false
        shuffledAnswers[2].isSelected = true
        mCallback.onClick(shuffledAnswers[2],position,it,holder.ans1,holder.ans2)
    }
 }

 interface OnItemClickListener{
      fun onClick(answerSelected: Answer?, questPosition: Int, selectedItemView: View, firstItemView: View, secondItemView: View)
 }

QuizFragment.kt

        mAdapter.setOnItemClickListener(object : QuizAdapter.OnItemClickListener{
            override fun onClick(answerSelected: Answer?,
                                 questPosition: Int,
                                 selectedItemView: View,
                                 firstItemView: View,
                                 secondItemView: View) {

                selectedItemView.background = ContextCompat.getDrawable(requireContext(),R.drawable.selected_ans_quiz)
                firstItemView.background = ContextCompat.getDrawable(requireContext(),R.drawable.default_ans_quiz)
                secondItemView.background = ContextCompat.getDrawable(requireContext(),R.drawable.default_ans_quiz)
                quizViewModel.chosenAnswers[questPosition] = answerSelected
            }
        })

推荐阅读