Получение значений EditTexts из RecyclerView - PullRequest
5 голосов
/ 23 мая 2019

Я создаю приложение, в котором пользователю необходимо заполнить некоторые данные для публикации чего-либо, поэтому фрагмент состоит из EditText, переключателей и Spinner вместе с RecyclerView, который динамически отображает несколько дочерних макетовсодержащие TextView и EditText.

Поэтому, когда пользователь выбирает категорию из Spinner, некоторые свойства, связанные с этой категорией, отображаются в RecyclerView, и пользователь может по желанию заполнить некоторые из них.

Я пытался реализоватьэта функция использует обратный вызов и TextWatcher, но я не получаю нужные значения.

CallBack

interface PropertiesCallback {
    fun addProp(position: Int, title: String, value: String)
}

Адаптер

class PropertiesAdapter(private val propertiesCallback: PropertiesCallback)
    : RecyclerView.Adapter<PropertiesAdapter.ViewHolder>() {

    private var list = listOf<CategoriesAndSubcategoriesQuery.Property>()

    fun setData(listOfProps: List<CategoriesAndSubcategoriesQuery.Property>) {
        this.list = listOfProps
        notifyDataSetChanged()
    }

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

    override fun getItemCount(): Int = list.size

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(list[position], position)
    }

    inner class ViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
        private val label: TextView = view.findViewById(R.id.label)
        private val input: EditText = view.findViewById(R.id.input)

        fun bind(prop: CategoriesAndSubcategoriesQuery.Property, position: Int) {
            label.text = prop.title()

            prop.hint()?.let { input.hint = prop.hint() }

            input.addTextChangedListener(object : TextWatcher {
                override fun afterTextChanged(s: Editable?) {}

                override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}

                override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                    propertiesCallback.addProp(position, prop.title(), input.text.toString())
                }
            })
        }
    }
}

In Fragment

private var propertiesList = mutableListOf<CategoriesAndSubcategoriesQuery.Property>()
private var propertiesInputList = mutableListOf<ProductPropertiesInput>()



  private fun setUpSubcategorySpinner() {
        subcategoriesAdapter = ArrayAdapter(
                this@AddProductFragment.context!!,
                android.R.layout.simple_spinner_item,
                subcategoriesList
        )
        //Subcategories
        subcategoriesAdapter.setDropDownViewResource(android.R.layout.simple_dropdown_item_1line)

        subcategory_spinner.adapter = subcategoriesAdapter

        subcategory_spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
            override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) {
                subcategoryId = subcategoriesList[position].id()

                //Adding properties
                subcategoriesList[position].properties()?.let {
                    //Clear previous properties data of another subcategory.
                    propertiesInputList.clear()
                    propertiesList.clear()

                    propertiesList.addAll(it)
                    propertiesAdapter.setData(propertiesList)
                    propertiesAdapter.notifyDataSetChanged()
                }
            }

            override fun onNothingSelected(parent: AdapterView<*>) {}
        }
    }

overide

 override fun addProp(position: Int, title: String, value: String) {
        val prop = ProductPropertiesInput
                .builder()
                .title(title)
                .value(value)
                .build()

        propertiesInputList.add(prop)

        //Log.d(TAG, "prop: ${prop.title()} : ${prop.value()}")
    }

submit fun

    private fun submitProduct() {
        //Initializing properties.
        val properties: Any

        //The keys needed in final list.
        val propertyKeys = propertiesList.map { it.title() }

        //Removing objects which keys are not needed.
        propertiesInputList.removeAll { it.title() !in propertyKeys }

        Log.d(TAG, "propertiesInputList: $propertiesInputList")

        //Removing duplicate and assign result in properties var.
        properties = propertiesInputList
                .distinctBy { it.title() }

        Log.d(TAG, "properties: $properties")

        for (prop in properties) {
        Log.d(TAG, "properties , title: ${prop.title()}, value: ${prop.value()} ")
    }
}

Выше коды предназначены для работы в качестве.Когда пользователь вводит значение в один из EditText в RecyclerView, оно будет фрагментировано и добавлено к объекту, который получает заголовок и значение, а затем добавлено к propertiesInputList.

Задача 1: propertiesInputList будет иметь так много дубликатов объектов с одинаковым названием, и я подумал, что лучшим решением было бы использовать distinctBy.

Задача 2: Когда пользователь заполняетчисло EditText, которое связано, скажем, с category1 и передумает и выберите другую категорию из Spinner.Предыдущие значения, которые не являются частью новой выбранной категории , остаются в списке propertiesInputList.Поэтому я подумал, что лучшим решением было бы очистить propertiesInputList и использовать removeAll с заголовками, относящимися к категории, для фильтрации нежелательных объектов.

Но теперь я получаю только первые буквы пользовательских типов.Если пользователь наберет обувь , я получу с .Таким образом, кажется, distinctBy возвращает первый объект, но я хочу, чтобы пользователь точно набрал последнее слово, и если пользователь напечатал и удалил все, что я хочу, пустым.

Есть ли лучшее решение для этого?Как зацикливание recyclerView только когда пользователь нажимает «отправить» вместо TextWatcher?Или какую часть я должен исправить, чтобы сделать эту работу?

Ответы [ 3 ]

3 голосов
/ 12 июня 2019

Я не совсем понимаю, чего вы пытаетесь достичь здесь.EditTexts внутри RecyclerView, как правило, не является хорошей идеей по следующим причинам.

  1. При прокрутке recyclerView вы хотели бы сохранить текст, добавленный пользователем для этого конкретного поля / элемента, и правильно отобразить его.когда пользователь прокручивает назад.
  2. Когда вы добавляете TextWatcher к EditText, вам также нужно удалить его, когда представление перезагружено или держатель представления снова привязан.В противном случае у вас будет несколько слушателей, и все пойдет не так.

Что касается другого вопроса, который у вас есть,

Но теперь я получаю только первое письмо пользователятипы.Если пользователь набирает обувь, я получаю s

Вот так задумано.TextWatcher будет генерировать событие каждый раз, когда вводится символ.Таким образом, вы получите s, sh, sho, shoes, shoes.Таким образом, вы не можете выполнить действие с этими данными, поскольку пользователь все еще добавляет что-то в это поле.


Итак,

  • Вы не знаете, когдапользователь прекратил добавлять текст в EditText (или был ли пользователь сделан).Вы можете использовать что-то вроде debounce, но это сложно.Вы должны дать кнопку пользователю.Примите значение, когда пользователь нажмет кнопку.

  • Я предполагаю, что у вас есть несколько правок редактирования в RecyclerView.Таким образом, вам нужно будет сохранить значения для каждого текста редактирования, потому что просмотрщик повторно будет использовать представления, и вы потеряете данные.Вы можете сделать это с помощью обратного вызова onViewRecycled вашего адаптера.Сохраняйте карту id -> string, где вы храните эти данные и извлекаете их, когда держатель представления связан.

  • Вы также можете использовать TextWatcher, но вам нужно было бы отсоединить его перед прикреплением новогоодин или в onViewRecycled.

Обновление:

Если бы у меня было что-то подобное, я бы использовал ScrollView с вертикальным LinearLayout (для простоты) и добавил бы EditTextисходя из требований.Если вы хотите добавить TextWatcher, вам понадобится какой-то стабильный идентификатор.

class EditTextContainer : LinearLayout {

    private val views = mutableListOf<EditText>()
    private val textWatchers = hashMapOf<Int, TextWatcher>()

    ... constructor and bunch of stuff

    fun updateViews(items: List<Item>, textCallback: (id, text) -> Unit) {
        // Remove text watchers
        views.forEach { view ->
             view.removeTextWatcher(textWatchers[view.id])
        }

        // More views than required
        while (views.size > items.size) {
            val view = views.removeAt(views.size-1)
            removeView(view)
        }

        // Less views than required
        while (view.size < items.size) {
            val view = createView()
            view.id = View.generateViewId()
            addView(view, createParams()) // Add this view to the container
            views.add(view)
        }

        // Update the views
        items.forEachIndexed { index, item ->
            val editText = views[item]
            // Update your edittext.
             addTextWatcher(editText, item.id, textCallback)
        }
    }

     private fun createView(): EditText {
         // Create new view using inflater or just constructor and return
     }

     private fun createParams(): LayoutParams {
         // Create layout params for the new view
     }

     private fun addTextWatcher(view, itemId, textCallback) {
         val watcher = create text watcher where it invokes textCallback with itemId
         view.addTextWatcher(watcher)
         textWatchers[view.id] = watcher
     }
}
1 голос
/ 12 июня 2019

Ваш вклад меньше, чтобы идентифицировать проблему. Я предполагаю, что вы делаете какое-то приложение для сбора данных со списком редактируемого текста. Существует проблема, когда вы использовали текст редактирования в списке переработчика. При прокрутке внизу редактируемый текст в представлении рециркулятора будет заполнен уже заполненным значением редактируемого текста, даже если ваш пользователь не заполнен.

В качестве обходного пути Вы можете создать какой-нибудь разреженный массив любой структуры данных, которая будет наиболее подходящей для вас, которая может отобразить ваше положение и ценность лайк mPropertyValue [] = новая строка [LIST_SIZE]. при условии, что позиция элемента списка совпадает с индексом массива.

Попробуйте обновить индекс значением наблюдателя текста mPropertyValue [POSITION] = YOUR_EDIT_TEXT_VALUE

Если вы хотите инициализировать ваш текст редактирования, используйте значение mPropertyValue [POSITION]

Вы всегда можете убедиться, что ваш текст редактирования будет иметь правильное значение.

0 голосов
/ 23 мая 2019

я сталкиваюсь с такой проблемой в моем коде Java, и это было решением

for (int i = 0; i < list.size(); i++) {
(put her the getter and setter class) mylist = list.get(i);
//use the getter class to get values and save them or do what ever you want
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...