【问题标题】:Another "RecyclerView duplicating items" question另一个“RecyclerView 重复项目”问题
【发布时间】:2021-09-19 20:43:29
【问题描述】:

我遇到了这个问题,花了几个小时探索这里找到的不同解决方案,但无法弄清楚。我有一个带有 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
            }

        })

【问题讨论】:

  • 您正在处理多少个项目?如果是 10 或 12 之类的小东西,只需使用普通的线性布局。 RecyclerView 不打算与输入一起使用,仅用于查看。您必须手动保存每个项目的状态并恢复它
  • 感谢您的回答。这是一个动态列表,但它可能不会超过 20 个项目。你是对的,我认为这是一个简单的线性布局的工作。谢谢,Ahmad Sattout!

标签: android kotlin android-recyclerview duplicates android-edittext


【解决方案1】:

RecyclerView 通常不用于 Input 视图。由于 Android 根据 ID 保存视图的输入,因此您的 RecyclerView 有 X 个视图,它们都具有相同的 ID,因此它们都使用相同的状态。

对此的解决方案是在recycle 方法中手动保存您的输入状态,并在bind 方法中恢复它。

所以如果你有 20 个项目,你就有 20 个状态。最初它们都是空的或默认的,并在需要保存时更改。

更简单的方法是使用 LinearLayout 或类似的布局来实现您的目标,但这取决于您拥有多少项目以及将包含多少视图。

不过,您仍然需要注意 View ID 部分

【讨论】:

    【解决方案2】:

    我曾尝试使用 ListView,但键盘却疯狂地改变了焦点。决定保留 RecyclerView,由于我的动态列表不是很大,所以我使用了

    holder.setIsRecyclable(false);
    

    在 OnBindViewHolder() 方法上,它解决了我的问题。谢谢大家的帮助

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-03-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多