在基于测验的应用程序中具有嵌套 setOnClickListener 的 RecyclerView

Posted

技术标签:

【中文标题】在基于测验的应用程序中具有嵌套 setOnClickListener 的 RecyclerView【英文标题】:RecyclerView with nested setOnClickListener in a quiz based app 【发布时间】:2021-06-24 08:29:37 【问题描述】:

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

这是我的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)
    
 

一切正常,但选择了答案:如果我选择第一个问题的答案 (myDataset[0]),列表中的 N+0 元素的视图也会发生变化,其中NRecyclerView 加载的最大项目块

如何在onBindViewHolder 加载的第N 个元素之后为每个子元素在RecyclerView 中设置正确的属性而不进行传播?

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

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

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 中可见的位置以及前面的其他位置)仍然混合在一起。

【问题讨论】:

【参考方案1】:

如果它有用,我找到了解决方案。 我向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
            
        )

【讨论】:

以上是关于在基于测验的应用程序中具有嵌套 setOnClickListener 的 RecyclerView的主要内容,如果未能解决你的问题,请参考以下文章

BQ数组查找:类似于NTH,但基于索引,而不是位置

自动为 Mysql 表行生成页面

多个嵌套集合字段和奏鸣曲类型集合

具有 display:table 样式的嵌套 div 在 IE 中不会拉伸到 100% 高度

QML中具有嵌套滚动区域的二维表

ROR:嵌套视图