Recyclerview Потеря данных редактируемого текста при прокрутке

#android #kotlin #android-recyclerview #android-adapter #notifydatasetchanged

Вопрос:

Я пытаюсь реализовать recyclerview, в котором есть список элементов 50-100. Каждая строка содержит представление TextView и представление Edittext. Пользователь вводит комментарии к каждой строке, содержащей редактируемый текст. Но проблема в том, что когда пользователь вводит значение и пытается прокрутить его вверх/вниз, данные, введенные в строку, теряются.

Затем я попробовал другое решение. Я обновляю значение массива в этой позиции и уведомляю об изменении, оно выводит значение во всех строках, содержащих редактируемый текст

Мой Адаптер:

 class MyAdapter(
    val context: Context,
    val itemList: MutableList<String>
) :
    RecyclerView.Adapter<MyAdapter.ViewHolder>() {
    
    class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        var txtLabel: TextView = view.findViewById(R.id.txtLabel)
        var etValue: EditText = view.findViewById(R.id.etValue)
        var watcher: TextWatcher? = null
    }

    override fun onCreateViewHolder(
        parent: ViewGroup,
        viewType: Int
    ): ViewHolder {
        val view =
            LayoutInflater.from(context).inflate(R.layout.list_comment, parent, false)
        return ViewHolder(view)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.txtLabel.text = itemList[position]
        holder.watcher = holder.etValue.doAfterTextChanged { text ->
            try {
                updateItem(
                    position,
                    text.toString()
                )

            } catch (ex: Exception) {
                println(ex.message)
            }
        }
    }

    override fun getItemCount(): Int {
        return itemList.size
    }

    fun updateItem(position: Int, item: String) {
        itemList.add(position, item)
        notifyDataSetChanged()
    }
}
 

При запуске метода updateItem он обновляет все строки, но я передаю позицию только для обновления в этой позиции. Пожалуйста, объясните, в чем проблема.

Комментарии:

1. В updateItem : Я думаю , вы имели в виду itemList.set(position, item) , что нет itemList.add(position, item) . notifyDataSetChanged() кажется, в этом нет необходимости.

2. add сделает то же самое, если мы передадим индекс вместе с ним. Это добавляет ценность при заданном индексе

3. Но таким образом вы создаете все больше и больше предметов в своем переработчике. Ты это имеешь в виду? Каждый раз, когда вы вставляете символ в редактируемый текст, вы добавляете новый элемент в recyler со значением текущего редактируемого текста.

4. Да, ваша точка зрения справедлива. Но это также меняет цвет представления текста, в котором пользователь ввел ввод. В этом случае я должен уведомить об этом()

5. Вы можете использовать etValue.onFocusChangeListener для изменения цвета TexView. (В каждый момент времени есть только один сфокусированный взгляд)

Ответ №1:

holder.etValue.doAfterTextChanged добавлю а TextChangedListener . Вы не удаляете его позже, и, таким образом, вы получаете несколько прослушивателей, прикрепленных к одному редактируемому тексту.

Вы могли бы переписать свой код следующим образом:

 class MyAdapter(
    val context: Context,
    val itemList: MutableList<String>
) : RecyclerView.Adapter<MyAdapter.ViewHolder>() {

    class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        lateinit var onTextUpdated: (String) -> Unit
        var txtLabel: TextView = view.findViewById(R.id.txtLabel)
        var etValue: EditText = view.findViewById(R.id.etValue)

        init { // TextChanged listener added only once.
            etValue.doAfterTextChanged { editable ->
                val text = editable.toString()
                onTextUpdated(text)
            }
        }
    }

    override fun onCreateViewHolder(
        parent: ViewGroup,
        viewType: Int
    ): ViewHolder {
        val view =
       LayoutInflater.from(context).inflate(R.layout.list_comment, parent, false)
        return ViewHolder(view)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.txtLabel.text = itemList[position]
        holder.onTextUpdated = { text -> // each time holder is bound, new listener will be assigned
            try {
                updateItem(
                    position,
                    text
                ) // update cached value
                holder.txtLabel.text = text // update label

            } catch (ex: Exception) {
                println(ex.message)
            }
        }
    }

    override fun getItemCount(): Int {
        return itemList.size
    }

    fun updateItem(position: Int, item: String) {
        itemList[position] = item
        // this might mess up the EditTexts focus. 
        // notifyDataSetChanged()
    }
}
 

Комментарии:

1. Это дает мне ошибку onTextUpdated, которая не была инициализирована

2. Должно быть, вы неправильно его изменили. onTextUpdated свойство должно быть установлено перед доступом к нему.

3. Да, я это сделал. Спасибо за помощь, братан