android - 从 RecyclerView 获取 EditTexts 值
问题描述
我正在构建一个应用程序,用户需要填写一些数据才能发布某些内容,因此一个片段由EditText
、 单选按钮组成,并且Spinner
与RecyclerView
它一起动态呈现许多包含TextView
和的子布局EditText
。
因此,当用户从中选择类别时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()} ")
}
}
以上代码旨在作为。当用户在其中一个值中键入一个值时,EditText
该RecyclerView
值将被分片并添加到一个对象中,该对象具有标题和值,然后添加到propertiesInputList
.
问题 1: propertiesInputList
会有这么多具有相同标题的重复对象,我认为最好的解决方案是使用distinctBy
.
问题 2:当用户填写了一些EditText
与假设相关的内容category1
并改变主意并从中选择另一个类别时Spinner
。不属于新选择的类别的先前值保留在propertiesInputList
列表中。所以我认为最好的解决方案是清除propertiesInputList
并使用removeAll
与类别相关的标题来过滤不需要的对象。
但现在我只得到用户类型的第一个字母。如果用户输入shoes我得到s。所以它似乎distinctBy
返回了第一个对象,但我想得到用户输入的最后一个单词,如果用户输入并删除了我想要空白的所有内容。
有没有更好的解决方案来处理这个问题?就像recyclerView
只有当用户按下提交而不是循环时才循环TextWatcher
?或者我应该修复哪个部分来完成这项工作?
解决方案
我不完全理解你在这里想要达到的目标。RecyclerView 中的 EditTexts 通常不是一个好主意,原因如下。
- 滚动 recyclerView 时,您可能希望保留用户为该特定字段/项目添加的文本,并在用户向后滚动时正确显示。
- 当你在
TextWatcher
一个 EditText 中添加 a 时,你也需要在视图被回收或者视图持有者被再次绑定时移除它。否则,你最终会得到多个听众,事情就会出错。
对于您的另一个问题,
但现在我只得到用户类型的第一个字母。如果用户输入鞋子,我会得到
这是设计使然。每次输入字符时,TextWatcher 都会发出事件。所以你会得到 s, sh, sho, shoe, shoes。因此,您不能对此数据采取行动,因为用户仍在向该字段添加内容。
所以,
您不知道用户何时停止将文本添加到 EditText(或用户是否已完成)。你可以使用类似的东西,
debounce
但这很复杂。你应该给用户一个按钮。当用户点击按钮时取值。我假设您在 RecyclerView 中有多个编辑文本。因此,您需要存储每个 edittext 的值,因为 recyclerview 将重新使用视图并且您将丢失数据。您可以在适配器的
onViewRecycled
回调中执行此操作。保留一个 id -> string 的映射,用于存储此数据并在绑定视图持有者时检索。您也可以使用 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
}
}
推荐阅读
- java - 当我尝试构建项目时,清单合并失败
- python-3.x - 基于公共字段“国家”组合 3 个数据帧
- three.js - 网格标准材料中的模糊光反射
- vue.js - `vue-cli-service build` 不生成模板的代码
- date - Vue没有显示日期值
- r - R 相关性:具有缺失数据的配对向量的条件处理
- javascript - 具有许多 X 值的缩放图表
- java - 当我使用递归函数时,它返回意外的结果
- wagtail - 如何使用“permissions_required”挂钩有效地将非 CMS 页面视图限制为 wagtail 中的用户组?
- maven - Maven - 通过 groupId 更新依赖项的命令行