Android嵌套RecyclerView获取所有输入框内容仅返回最后项如何解决
核心问题
你拿不到第一个父项内容的根本原因是MainAdapter里的parentItemHolder和childAdapter被声明为全局变量,每次onBindViewHolder绑定新的父项时,这两个变量都会被覆盖成当前父项的实例,最终只会保留最后一个父项的相关引用,所以读取时只能拿到最后一个父项的4条数据。
除此之外还有几个常见错误:
- 没有为每个父项单独保存对应的子Adapter实例,遍历所有父项时找不到对应子列表的入口
- 没有给子项的EditText加文本变化监听,用户输入的内容不会同步到子Adapter的数据集里,直接读View很容易因为RecyclerView复用逻辑拿到错误内容
- 读取数据时直接遍历ViewHolder,超出屏幕的ViewHolder会被回收,拿不到不可见区域的输入内容
修改方案
1. 改造MainAdapter,保存每个父项的子Adapter
class MainAdapter(var locationList: ArrayList<HashMap<String, String>>): RecyclerView.Adapter<MainAdapter.ViewHolder>() { val byDates = locationList.groupBy { it["time"] } // 用列表保存每个父位置对应的子Adapter private val childAdapters = mutableListOf<PropertyAdapter>() @SuppressLint("WrongConstant") override fun onBindViewHolder(holder: MainAdapter.ViewHolder, position: Int) { val sdf = SimpleDateFormat("MM/dd/yyyy") val dateList = byDates.values.toMutableList() holder.date?.text = sdf.format(dateList[position][0].get("time")?.toLong()) holder.childRv?.layoutManager = LinearLayoutManager(holder.childRv.context, LinearLayout.VERTICAL, false) // 每个父项单独维护自己的子数据集 val properyDataList:ArrayList<propertyDataClass> = ArrayList() val childAdapter = PropertyAdapter(properyDataList) holder.childRv.adapter = childAdapter // 把当前父项的子Adapter存入列表 if (position >= childAdapters.size) { childAdapters.add(childAdapter) } else { childAdapters[position] = childAdapter } holder.date?.setOnClickListener(View.OnClickListener { properyDataList.add(propertyDataClass()) childAdapter.notifyDataSetChanged() }) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MainAdapter.ViewHolder { val v = LayoutInflater.from(parent.context).inflate(R.layout.recyclerview_item_dates, parent, false) return ViewHolder(v) } override fun getItemCount(): Int { return byDates.count() } class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) { val date = itemView.findViewById<TextView>(R.id.locationDate) val childRv = itemView.findViewById<RecyclerView>(R.id.childList) } fun getAllItemDetails():ArrayList<String>{ val stringList = ArrayList<String>() try { // 遍历所有父项的子Adapter childAdapters.forEach { childAdapter -> // 调用子Adapter的方法拿所有输入内容 val childValues = childAdapter.getAllItemValues() stringList.addAll(childValues) } }catch (e:Exception){ e.printStackTrace() } return stringList } }
2. 改造PropertyAdapter,同步输入内容到数据集
class PropertyAdapter( val propertyList: ArrayList<propertyDataClass>, ): RecyclerView.Adapter<PropertyAdapter.ViewHolder>() { override fun onBindViewHolder(holder: PropertyAdapter.ViewHolder, position: Int) { val propertyItem = propertyList[position] holder.etLabel?.text = propertyItem.inputName holder.etValue?.setText(propertyItem.inputValue) // 移除之前的监听避免复用冲突 holder.etValue?.removeTextChangedListener(holder.textWatcher) // 给输入框加监听,内容变化实时更新到数据集 holder.textWatcher = 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?) { propertyItem.inputValue = s?.toString() ?: "" } } holder.etValue?.addTextChangedListener(holder.textWatcher) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PropertyAdapter.ViewHolder { val v = LayoutInflater.from(parent.context).inflate(R.layout.recyclerview_item_locations, parent, false) return ViewHolder(v) } override fun getItemCount(): Int { return propertyList.size } class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) { val etLabel = itemView.findViewById<TextView>(R.id.etLabel) val etValue = itemView.findViewById<EditText>(R.id.etValue) // 保存当前item的文本监听实例,避免复用冲突 var textWatcher: TextWatcher? = null } // 新增方法返回所有子项的输入值 fun getAllItemValues(): List<String> { return propertyList.map { it.inputValue } } }
修改后点击MainActivity的TextView即可拿到所有父项+子项的全部输入内容。
内容的提问来源于stack exchange,提问作者Kumar Bankesh
相关产品推荐
相关产品推荐

