异构RecyclerView条目动态加载未知数量EditText实现方案
动态未知数量EditText的RecyclerView适配方案
核心逻辑不需要提前定义多套异构布局,现有适配器基础逻辑完全不用改动,直接复用现有通用条目布局,在条目内置的parent_edittext垂直容器中,根据JSON返回的字段配置动态增减EditText即可,完全适配数量不固定的场景。
1. 补全数据模型,解决复用输入丢失问题
首先在自定义字段的数据类中增加输入内容存储字段,避免RecyclerView滚动复用的时候输入内容错乱、丢失:
data class DisplayCustomFields( // 以下字段替换为你JSON实际返回的字段属性即可 val fieldId: Int, // 字段唯一标识 val fieldLabel: String, // 字段名称 val placeholder: String? = null, // 输入框提示文本 var inputValue: String? = null // 存储用户输入内容,必须声明为var可变类型 )
2. 修改ViewHolder绑定逻辑,动态加载EditText
直接修改现有Base_DisplayViewHolder的bind方法,每次绑定条目时先清理容器内复用残留的旧控件,再根据当前条目的自定义字段数量逐个生成EditText加入容器,同时绑定文本监听实时存储输入内容:
class Base_DisplayViewHolder( private val itemBinding: ItemDisplayBinding, private val listener: Adapter_base_Display.Base_DisplayListener, private val activityIns: FragmentActivity, private var parent: ViewGroup, private val items: ArrayList<DisplaySections>, ) : RecyclerView.ViewHolder(itemBinding.root), View.OnClickListener { // 缓存当前绑定的条目数据、文本监听器,避免复用导致内容错乱、内存泄漏 private var currentBoundItem: DisplaySections? = null private val textWatcherMap = hashMapOf<Int, TextWatcher>() init { itemBinding.root.setOnClickListener(this) } fun bind(item: DisplaySections) { currentBoundItem = item itemBinding.textView2.text = item.name val editTextContainer = itemBinding.parentEdittext // 清空容器内旧控件、移除旧监听器 editTextContainer.removeAllViews() textWatcherMap.values.forEach { watcher -> // 遍历移除所有旧文本监听,防止内存泄漏 } textWatcherMap.clear() // 遍历当前条目的自定义字段,逐个生成EditText item.displayCustomFields.forEach { customField -> // 加载你预定义的EditText布局,布局名替换成你项目里的实际文件名 val editText = LayoutInflater.from(itemBinding.root.context) .inflate(R.layout.item_edittext_display, editTextContainer, false) as EditText // 配置EditText属性 editText.hint = customField.placeholder ?: customField.fieldLabel editText.setText(customField.inputValue) editText.tag = customField.fieldId // 绑定文本输入监听,实时存输入内容到数据模型 val watcher = object : TextWatcher { override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {} override fun afterTextChanged(s: Editable?) { customField.inputValue = s?.toString() } } editText.addTextChangedListener(watcher) textWatcherMap[customField.fieldId] = watcher // 将配置好的EditText加入容器 editTextContainer.addView(editText) } } override fun onClick(v: View?) { listener.onClickeddisplay(adapterPosition) } }
注意:你贴出的条目基础布局缺少最外层根布局标签,记得补一个orientation为vertical的LinearLayout作为根容器,否则布局加载会报错。ViewBinding会自动把下划线命名的id转成驼峰,比如
parent_edittext对应绑定类里的parentEdittext,和代码保持一致即可。
3. 性能优化(可选)
如果单条目的自定义字段数量较多(超过10个),可以不用每次绑定都全量删除重建EditText,改成简单的View缓存逻辑:
- 容器内已有EditText数量多于需要展示的数量时,把多余的EditText设为
GONE隐藏即可 - 数量不足时再inflate新的EditText补入
- 复用已有EditText时先移除旧的文本监听器,再绑定新的数据
字段数量少的场景下全量删建完全不会有性能问题,不需要额外优化。
4. 输入内容获取
最终需要提交表单或者获取用户输入时,直接遍历适配器中存储的items列表即可,每个DisplaySections下displayCustomFields中的inputValue字段就是用户对应输入的内容,不需要遍历View查找取值。
内容的提问来源于stack exchange,提问作者Meher Khemiri
相关产品推荐
相关产品推荐

