巴士座位预订选中与取消选中的位置异常问题
解决巴士座位预订RecyclerView的状态错乱问题
这种问题我之前做类似座位选择控件时也碰到过,核心原因基本都是RecyclerView的ViewHolder复用机制在搞鬼,咱们一步步拆解解决:
1. 点击座位时控件状态错位(点第一个,第五个变)
这是典型的复用导致的状态残留问题——当RecyclerView复用ViewHolder时,之前设置的状态没有被正确重置,比如原本显示第一个座位的ViewHolder被拿来显示第五个座位,就会把之前的选中状态带过去。
解决思路:
所有座位的状态(选中/未选中、座位号)都要存在数据源里,而不是ViewHolder中。每次操作只修改数据源,再通知RecyclerView更新对应位置:
- 先定义一个数据类来保存座位的所有状态:
data class Seat( val seatNumber: String, var isSelected: Boolean = false, val isAisle: Boolean = false // 标记是否是过道位置 ) - 在Adapter的
onBindViewHolder中,严格根据数据源的状态来设置控件,而不是只在点击事件里修改:override fun onBindViewHolder(holder: SeatViewHolder, position: Int) { val currentSeat = seatList[position] // 先根据数据重置所有状态 holder.seatImg.setImageResource( if (currentSeat.isSelected) R.drawable.ic_seat_selected else R.drawable.ic_seat_normal ) holder.seatNumberTv.text = currentSeat.seatNumber holder.itemView.isClickable = !currentSeat.isAisle // 处理点击事件:只修改数据源,再通知更新 holder.itemView.setOnClickListener { currentSeat.isSelected = !currentSeat.isSelected // 只更新当前位置,避免全量刷新影响性能 notifyItemChanged(position) } }
2. 座位号有时显示空白
这个问题同样和复用+数据源对应关系有关:当ViewHolder被复用给过道位置(不需要显示座位号),或者数据源的位置和GridLayoutManager的列数不匹配时,就会出现空白或错位。
解决思路:
- 构建数据源时,严格对应GridLayoutManager的5列结构:每行5个位置,其中第3个(索引从0开始是2)是过道,标记
isAisle = true;最后一行不需要过道,所以5个都是普通座位。 - 在
onBindViewHolder中判断是否是过道位置,单独处理:override fun onBindViewHolder(holder: SeatViewHolder, position: Int) { val currentSeat = seatList[position] if (currentSeat.isAisle) { // 过道位置:隐藏座位图,清空号码,禁止点击 holder.seatImg.visibility = View.INVISIBLE holder.seatNumberTv.text = "" holder.itemView.isClickable = false return } // 普通座位:正常设置状态 holder.seatImg.visibility = View.VISIBLE holder.seatNumberTv.text = currentSeat.seatNumber holder.seatImg.setImageResource( if (currentSeat.isSelected) R.drawable.ic_seat_selected else R.drawable.ic_seat_normal ) holder.itemView.isClickable = true holder.itemView.setOnClickListener { currentSeat.isSelected = !currentSeat.isSelected notifyItemChanged(position) } }
额外提醒
- 不要直接在ViewHolder中保存任何状态,所有状态都要委托给数据源,因为ViewHolder会在滚动时被反复复用。
- 如果最后一行的座位数和其他行不同,构建数据源时要单独处理该行的位置,确保每个位置的
isAisle和seatNumber都正确。
内容的提问来源于stack exchange,提问作者user9751732
相关产品推荐
相关产品推荐

