You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

巴士座位预订选中与取消选中的位置异常问题

解决巴士座位预订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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 03:50:48