在基于测验的应用程序中使用嵌套的 setOnClickListener 的 RecyclerView
RecyclerView with nested setOnClickListener in a quiz based app
我对基于测验的应用程序的基本功能的实现有疑问。简而言之,我在 ArrayList<Question>
中有“问题”和“答案”(对于此示例,每个 Question
都有自己的 ArrayList<Answer>
、3)我曾经在使用 MVVM 管理的片段中填充 RecyclerView
的适配器。
这是我的 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)
}
}
一切正常,但 select 的答案:如果我 select 第一个问题的答案 (myDataset[0]
),[=43] 的视图也会发生变化=]N+0 列表中的元素,其中 N 是由 RecyclerView
加载的项目的最大块数
如何在 RecyclerView
中为每个子元素设置正确的属性而不在 onBindViewHolder
加载的第 N 个 元素之后传播?
可以修复还是我必须改变实现方式?
编辑:我刚刚尝试了另一种方法,但结果相同,使用的是接口:
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,我可以测试 selected 答案的正确性,看起来没问题,地图上充满了用户选择,即使 [=50] 有变化=]ion(地图位置,代表问题,修改正确)。
但是背景颜色在不同的位置保持混合(当前在 RecyclerView 中可见的颜色加上前面的其他颜色),如前所述。
如果有用的话,我找到了解决办法。
我向 Answer
class 添加了一个布尔值,以便 RecyclerView
必须检查何时在 xml 中构建其列表,混合我之前所做的 [=16] =]
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
}
})
我对基于测验的应用程序的基本功能的实现有疑问。简而言之,我在 ArrayList<Question>
中有“问题”和“答案”(对于此示例,每个 Question
都有自己的 ArrayList<Answer>
、3)我曾经在使用 MVVM 管理的片段中填充 RecyclerView
的适配器。
这是我的 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)
}
}
一切正常,但 select 的答案:如果我 select 第一个问题的答案 (myDataset[0]
),[=43] 的视图也会发生变化=]N+0 列表中的元素,其中 N 是由 RecyclerView
如何在 RecyclerView
中为每个子元素设置正确的属性而不在 onBindViewHolder
加载的第 N 个 元素之后传播?
可以修复还是我必须改变实现方式?
编辑:我刚刚尝试了另一种方法,但结果相同,使用的是接口:
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,我可以测试 selected 答案的正确性,看起来没问题,地图上充满了用户选择,即使 [=50] 有变化=]ion(地图位置,代表问题,修改正确)。 但是背景颜色在不同的位置保持混合(当前在 RecyclerView 中可见的颜色加上前面的其他颜色),如前所述。
如果有用的话,我找到了解决办法。
我向 Answer
class 添加了一个布尔值,以便 RecyclerView
必须检查何时在 xml 中构建其列表,混合我之前所做的 [=16] =]
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
}
})