【问题标题】:Getting EditTexts Values From RecyclerView从 RecyclerView 获取 EditTexts 值
【发布时间】:2019-05-22 22:43:26
【问题描述】:

我正在构建一个应用程序,用户需要填写一些数据才能发布内容,因此片段由EditText、单选按钮和Spinner 以及动态呈现多个子布局的RecyclerView 组成包含TextViewEditText

因此,当用户从Spinner 中选择类别时,与该类别相关的一些属性会显示在RecyclerView 中,用户可以选择填充其中的一些。

我尝试使用回调和TextWatcher 来实现此功能,但我没有得到我想要的值。

回调

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())
                }
            })
        }
    }
}

在片段中

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<*>) {}
        }
    }

覆盖

 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()}")
    }

提交乐趣

    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()} ")
    }
}

以上代码旨在用作。当用户在RecyclerView 中的EditText 之一中键入一个值时,该值将被分片并添加到具有标题和值的对象中,然后添加到propertiesInputList

问题 1: propertiesInputList 会有很多具有相同标题的重复对象,我认为最好的解决方案是使用 distinctBy

问题 2: 当用户填写一些与假设category1 相关的EditText 并改变主意并从Spinner 中选择另一个类别时。 不属于新选择的类别的先前值仍保留在propertiesInputList 列表中。所以我认为最好的解决方案是清除propertiesInputList 并使用removeAll 与类别相关的标题来过滤不需要的对象。

但现在我只得到用户类型的第一个字母。如果用户输入 shoes,我会得到 s。所以似乎distinctBy 返回了第一个对象,但我想得到用户输入的最后一个字,如果用户输入并删除了我想要空白的所有内容。

有没有更好的解决方案来处理这个问题?就像循环recyclerView 仅当用户按下提交而不是TextWatcher 时?或者我应该修复哪个部分来完成这项工作?

【问题讨论】:

    标签: android kotlin android-recyclerview


    【解决方案1】:

    我不完全理解您在这里想要达到的目标。 RecyclerView 中的 EditTexts 通常不是一个好主意,原因如下。

    1. 当 recyclerView 滚动时,您可能希望保留 用户为该特定字段/项目添加的文本并显示它 当用户向后滚动时正确。
    2. 在EditText中添加TextWatcher时,也需要在视图被回收或视图持有者再次绑定时将其移除。否则,你最终会得到多个监听器,事情就会出错。

    对于您的其他问题,

    但现在我只得到用户类型的第一个字母。如果用户输入鞋子,我会得到 s

    这是设计使然。每次输入字符时,TextWatcher 都会发出事件。所以你会得到 s, sh, sho, shoe, shoes。因此,您不能对这些数据采取行动,因为用户仍在向该字段添加内容。


    所以,

    • 您不知道用户何时停止向 EditText 添加文本(或者用户是否已完成)。你可以使用debounce 之类的东西,但这很复杂。你应该给用户一个按钮。获取用户点击按钮时的值。

    • 我假设您在 RecyclerView 中有多个编辑文本。因此,您需要存储每个 edittext 的值,因为 recyclerview 将重新使用视图并且您将丢失数据。您可以在适配器的 onViewRecycled 回调中执行此操作。保留一个 id -> 字符串的映射,用于存储此数据并在绑定视图持有者时检索。

    • 您也可以使用 TextWatcher,但您需要在附加新的之前将其分离或在 onViewRecycled 中。

    更新:

    如果我有这样的东西,我会使用带有垂直 LinearLayout 的 ScrollView(为简单起见)并根据要求添加 EditText。如果要添加 TextWatcher,则需要某种稳定的 id。

    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
         }
    }
    

    【讨论】:

    • RecyclerView 中的EditTexts 通常不是一个好主意 - 我同意是否有另一种方法可以动态呈现多个编辑文本?
    • 我会说,使用 ScrollView 并根据您的需要添加 EditText。例如。如果您需要 5 个编辑文本,请创建 5 个新视图并手动添加到 ScrollView 的容器中。如果数字发生变化,添加/删除 EditText,
    • 让我试一试
    【解决方案2】:

    您的输入不足以识别问题。我猜您正在使用编辑文本列表制作一些数据收集应用程序。 使用回收站列表中的编辑文本时出现问题。 当您向下滚动回收站视图中的底部编辑文本时,将填充已填充的编辑文本值,即使您的用户未填充。

    作为一种解决方法,您可以创建一些稀疏数组,任何最适合您的数据结构,可以映射您的位置和值 喜欢 mPropertyValue[] = 新字符串 [LIST_SIZE]。 , 假设你的列表项的位置与数组的索引匹配。

    尝试使用 text watcher 的值更新索引 mPropertyValue[POSITION] = YOUR_EDIT_TEXT_VALUE

    当你想初始化你的编辑文本时,使用 mPropertyValue[POSITION] 的值

    您始终可以确保您的编辑文本具有正确的值。

    【讨论】:

      【解决方案3】:

      我在我的 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
      }
      

      【讨论】:

      • 列表应该在哪里?
      • 私有变量列表 = listOf()
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-20
      • 1970-01-01
      • 1970-01-01
      • 2021-12-07
      • 2020-09-14
      • 1970-01-01
      相关资源
      最近更新 更多