另一个 "RecyclerView duplicating items" 个问题
Another "RecyclerView duplicating items" question
我遇到了这个问题,花了几个小时探索在这里找到的不同解决方案,但无法弄清楚。我有一个带有 RadioGroup(带有两个 RadioButton)和一个 EditText 的 RecyclerView。正如预期的那样,文本在滚动上不断重复,“原始”被删除。单选按钮也是如此。我试图在回收视图时将值保存在另一个数组备份上,但无法解决重复问题。
这是我的适配器
class ServicesCheckoutAdapter(var context: Context,
var servicesList: List<Service>) : RecyclerView.Adapter<ServicesCheckoutAdapter.ViewHolder>() {
private lateinit var onRadioGroupClickListener: OnRadioGroupClickListener
private lateinit var onTextChangedListener: OnTextChangedListener
private lateinit var onServiceClickListener: OnServiceClickListener
private var externalArray = mutableListOf<String>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(context).inflate(R.layout.services_list_item,
parent, false)
val viewHolder = ViewHolder(view)
val position = viewHolder.adapterPosition
view.setOnClickListener {
if (onServiceClickListener != null) {
onServiceClickListener.onServiceClick(view, servicesList[position].id, position)
}
}
return viewHolder
}
override fun getItemId(position: Int): Long {
return super.getItemId(position)
}
override fun getItemViewType(position: Int): Int {
return super.getItemViewType(position)
}
interface OnServiceClickListener {
fun onServiceClick(view: View, serviceId: Int, position: Int)
}
fun setOnServiceClickListener(listener: OnServiceClickListener)
{
onServiceClickListener = listener
}
interface OnRadioGroupClickListener {
fun onRadioGroupClick(buttonId: Int, serviceId: Int, position: Int) {}
}
fun setOnRadioButtonClickListener(listener: OnRadioGroupClickListener) {
onRadioGroupClickListener = listener
}
interface OnTextChangedListener{
fun onTextChanged(position: Int, text: String)
}
fun setOnTextChangedListener(listener: OnTextChangedListener){
onTextChangedListener = listener
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
Log.d("recycler", "lista: ${servicesList[position].serviceSolution}")
holder.edtSolution.removeTextChangedListener(holder.watcher)
holder.bind(context,
servicesList[position].id,
servicesList[position].name,
servicesList[position].serviceSolved,
servicesList[position].serviceSolution,
onRadioGroupClickListener,
onTextChangedListener,
position)
}
override fun getItemCount(): Int {
return servicesList.size
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var radioGroup = itemView.findViewById<RadioGroup>(R.id.radioGroupService)
val edtSolution = itemView.findViewById<EditText>(R.id.editTextCheckoutDesc)
var watcher: TextWatcher? = null
fun bind(context: Context,
serviceId: Int,
serviceName: String,
serviceSolved: Boolean,
serviceSolution: String,
onRadioGroupClickListener: OnRadioGroupClickListener,
onTextChangedListener: OnTextChangedListener,
position: Int
) {
itemView.findViewById<TextView>(R.id.serviceTitle)
.text = context.resources
.getString(R.string.service_title_comma, serviceName)
itemView.findViewById<RadioGroup>(R.id.radioGroupService)
.setOnClickListener {
onRadioGroupClickListener
.onRadioGroupClick(
(it as RadioGroup).checkedRadioButtonId, serviceId, adapterPosition)
}
if (serviceSolved) {
radioGroup.find<RadioButton>(R.id.radioBtnYes).isChecked = true
radioGroup.find<RadioButton>(R.id.radioBtnNo).isChecked = false
} else {
radioGroup.find<RadioButton>(R.id.radioBtnYes).isChecked = false
radioGroup.find<RadioButton>(R.id.radioBtnNo).isChecked = true
}
edtSolution.addTextChangedListener(object: TextWatcher{
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
onTextChangedListener.onTextChanged(position, s.toString())
}
override fun afterTextChanged(s: Editable?) {
}
})
}
}
}
这是 activity
上的适配器初始化
serviceList = occurrence.services
servicesAdapter = ServicesCheckoutAdapter(this, serviceList)
recyclerViewServices.adapter = servicesAdapter
recyclerViewServices.layoutManager = LinearLayoutManager(this)
servicesAdapter.setOnRadioButtonClickListener(object : ServicesCheckoutAdapter.OnRadioGroupClickListener {
override fun onRadioGroupClick(buttonId: Int, serviceId: Int, position: Int) {
super.onRadioGroupClick(buttonId, serviceId, position)
when (buttonId) {
R.id.radioBtnYes -> {
serviceList[position].serviceSolved = true
servicesAdapter.notifyDataSetChanged()
}
R.id.radioBtnNo -> {
serviceList[position].serviceSolved = false
servicesAdapter.notifyDataSetChanged()
}
}
}
})
servicesAdapter.setOnTextChangedListener(object : ServicesCheckoutAdapter.OnTextChangedListener{
override fun onTextChanged(position: Int, text: String) {
serviceList[position].serviceSolution = text
}
})
RecyclerView 通常不是为输入视图制作的。由于 Android 根据其 ID 保存视图的输入,因此您的 RecyclerView 有 X 个具有相同 ID 的视图,因此它们都使用相同的状态。
解决此问题的方法是在 recycle
方法中手动保存您的输入状态,然后在 bind
方法中恢复它。
所以如果你有 20 个项目,你就有 20 个状态。初始都是空的或者默认的,需要保存的时候再改。
更简单的方法是使用 LinearLayout 或类似的布局来实现您的目标,但这取决于您拥有多少项目以及将包含多少视图。
不过您仍然需要注意视图 ID 部分
我曾尝试使用 ListView,但键盘疯狂地改变了焦点。决定保留 RecyclerView,因为我的动态列表不是很大,所以我使用了
holder.setIsRecyclable(false);
在 OnBindViewHolder() 方法上,它解决了我的问题。感谢大家的帮助
我遇到了这个问题,花了几个小时探索在这里找到的不同解决方案,但无法弄清楚。我有一个带有 RadioGroup(带有两个 RadioButton)和一个 EditText 的 RecyclerView。正如预期的那样,文本在滚动上不断重复,“原始”被删除。单选按钮也是如此。我试图在回收视图时将值保存在另一个数组备份上,但无法解决重复问题。
这是我的适配器
class ServicesCheckoutAdapter(var context: Context,
var servicesList: List<Service>) : RecyclerView.Adapter<ServicesCheckoutAdapter.ViewHolder>() {
private lateinit var onRadioGroupClickListener: OnRadioGroupClickListener
private lateinit var onTextChangedListener: OnTextChangedListener
private lateinit var onServiceClickListener: OnServiceClickListener
private var externalArray = mutableListOf<String>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(context).inflate(R.layout.services_list_item,
parent, false)
val viewHolder = ViewHolder(view)
val position = viewHolder.adapterPosition
view.setOnClickListener {
if (onServiceClickListener != null) {
onServiceClickListener.onServiceClick(view, servicesList[position].id, position)
}
}
return viewHolder
}
override fun getItemId(position: Int): Long {
return super.getItemId(position)
}
override fun getItemViewType(position: Int): Int {
return super.getItemViewType(position)
}
interface OnServiceClickListener {
fun onServiceClick(view: View, serviceId: Int, position: Int)
}
fun setOnServiceClickListener(listener: OnServiceClickListener)
{
onServiceClickListener = listener
}
interface OnRadioGroupClickListener {
fun onRadioGroupClick(buttonId: Int, serviceId: Int, position: Int) {}
}
fun setOnRadioButtonClickListener(listener: OnRadioGroupClickListener) {
onRadioGroupClickListener = listener
}
interface OnTextChangedListener{
fun onTextChanged(position: Int, text: String)
}
fun setOnTextChangedListener(listener: OnTextChangedListener){
onTextChangedListener = listener
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
Log.d("recycler", "lista: ${servicesList[position].serviceSolution}")
holder.edtSolution.removeTextChangedListener(holder.watcher)
holder.bind(context,
servicesList[position].id,
servicesList[position].name,
servicesList[position].serviceSolved,
servicesList[position].serviceSolution,
onRadioGroupClickListener,
onTextChangedListener,
position)
}
override fun getItemCount(): Int {
return servicesList.size
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var radioGroup = itemView.findViewById<RadioGroup>(R.id.radioGroupService)
val edtSolution = itemView.findViewById<EditText>(R.id.editTextCheckoutDesc)
var watcher: TextWatcher? = null
fun bind(context: Context,
serviceId: Int,
serviceName: String,
serviceSolved: Boolean,
serviceSolution: String,
onRadioGroupClickListener: OnRadioGroupClickListener,
onTextChangedListener: OnTextChangedListener,
position: Int
) {
itemView.findViewById<TextView>(R.id.serviceTitle)
.text = context.resources
.getString(R.string.service_title_comma, serviceName)
itemView.findViewById<RadioGroup>(R.id.radioGroupService)
.setOnClickListener {
onRadioGroupClickListener
.onRadioGroupClick(
(it as RadioGroup).checkedRadioButtonId, serviceId, adapterPosition)
}
if (serviceSolved) {
radioGroup.find<RadioButton>(R.id.radioBtnYes).isChecked = true
radioGroup.find<RadioButton>(R.id.radioBtnNo).isChecked = false
} else {
radioGroup.find<RadioButton>(R.id.radioBtnYes).isChecked = false
radioGroup.find<RadioButton>(R.id.radioBtnNo).isChecked = true
}
edtSolution.addTextChangedListener(object: TextWatcher{
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
onTextChangedListener.onTextChanged(position, s.toString())
}
override fun afterTextChanged(s: Editable?) {
}
})
}
}
}
这是 activity
上的适配器初始化serviceList = occurrence.services
servicesAdapter = ServicesCheckoutAdapter(this, serviceList)
recyclerViewServices.adapter = servicesAdapter
recyclerViewServices.layoutManager = LinearLayoutManager(this)
servicesAdapter.setOnRadioButtonClickListener(object : ServicesCheckoutAdapter.OnRadioGroupClickListener {
override fun onRadioGroupClick(buttonId: Int, serviceId: Int, position: Int) {
super.onRadioGroupClick(buttonId, serviceId, position)
when (buttonId) {
R.id.radioBtnYes -> {
serviceList[position].serviceSolved = true
servicesAdapter.notifyDataSetChanged()
}
R.id.radioBtnNo -> {
serviceList[position].serviceSolved = false
servicesAdapter.notifyDataSetChanged()
}
}
}
})
servicesAdapter.setOnTextChangedListener(object : ServicesCheckoutAdapter.OnTextChangedListener{
override fun onTextChanged(position: Int, text: String) {
serviceList[position].serviceSolution = text
}
})
RecyclerView 通常不是为输入视图制作的。由于 Android 根据其 ID 保存视图的输入,因此您的 RecyclerView 有 X 个具有相同 ID 的视图,因此它们都使用相同的状态。
解决此问题的方法是在 recycle
方法中手动保存您的输入状态,然后在 bind
方法中恢复它。
所以如果你有 20 个项目,你就有 20 个状态。初始都是空的或者默认的,需要保存的时候再改。
更简单的方法是使用 LinearLayout 或类似的布局来实现您的目标,但这取决于您拥有多少项目以及将包含多少视图。
不过您仍然需要注意视图 ID 部分
我曾尝试使用 ListView,但键盘疯狂地改变了焦点。决定保留 RecyclerView,因为我的动态列表不是很大,所以我使用了
holder.setIsRecyclable(false);
在 OnBindViewHolder() 方法上,它解决了我的问题。感谢大家的帮助