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

Swift 4中UITableView点击按钮切换图片出现错乱问题求助

解决UITableView按钮点击后多行同步变化的问题

嘿,这个问题我太熟了——这完全是UITableView的单元格复用机制在搞鬼!当你滚动表格时,系统会把滑出屏幕的cell回收,再利用给新出现的行。你现在的代码直接修改cell上的按钮图片,但没有在cell复用的时候从数据源同步正确的状态,所以就出现了“点一个按钮,其他复用的行按钮也跟着变”的诡异情况。

问题根源

你在按钮点击事件里直接修改了cell的按钮图片,但这个状态没有和数据源(services数组)绑定到一起。当cell被复用到其他行时,它会带着之前修改的图片状态,看起来就像是其他行的按钮也被点击了。

修复方案(核心:数据源驱动UI)

我们要保证所有UI状态都从数据源读取,修改状态时先更新数据源,再让表格刷新对应的行。

1. 修正cellForRowAt方法,根据数据源设置按钮状态

每次cell被创建或复用的时候,都要从services数组里读取当前行的选中状态,设置按钮的正确图片:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell:ServicesCell = servicestable.dequeueReusableCell(withIdentifier: "servicess", for: indexPath) as! ServicesCell
    cell.name.text = services[indexPath.row].name
    let photo = services[indexPath.row].icon
    let imgURL = MainUrl + photo! 
    let url = URL(string: imgURL)
    cell.icon.kf.setImage(with: url)
    
    // 关键:根据数据源的choose字段设置按钮图片
    let isSelected = services[indexPath.row].choose == "1"
    let targetImage = isSelected ? UIImage(named: "Rectangle1") : UIImage(named: "checkbox1")
    cell.check.setImage(targetImage, for: .normal)
    
    cell.check.tag = indexPath.row
    cell.check.addTarget(self, action: #selector(self.btnAction(_:)), for: .touchUpInside)
    cell.checkpay.tag = indexPath.row
    cell.checkpay.addTarget(self, action: #selector(self.btnAction2(_:)), for: .touchUpInside)
    cell.price.addTarget(self, action: #selector(self.endedit(_:)), for: .editingDidEnd)
    cell.price.addTarget(self, action: #selector(self.endedit(_:)), for: .editingChanged)
    cell.selectionStyle = .none
    return cell
}

2. 修正按钮点击事件,先更新数据源再刷新行

点击按钮时,先修改services数组里的状态,然后只刷新对应的行,让表格重新调用cellForRowAt设置正确的UI:

@objc func btnAction(_ sender: UIButton) {
    let row = sender.tag
    let indexPath = IndexPath(row: row, section: 0)
    
    // 先更新数据源的状态
    let currentStatus = services[indexPath.row].choose
    if currentStatus == "0" {
        services[indexPath.row].choose = "1"
        chooseservicesw.updateValue("0", forKey: String(indexPath.row+1))
    } else {
        services[indexPath.row].choose = "0"
        chooseservicesw.removeValue(forKey: String(indexPath.row+1))
    }
    
    // 只刷新当前行,高效且避免其他行状态混乱
    servicestable.reloadRows(at: [indexPath], with: .automatic)
    
    print("number: \(indexPath.row)")
}

额外小建议

把services模型里的choose字段从字符串类型改成Bool(比如var isChosen: Bool),这样判断状态的时候不用做字符串比较,代码更简洁,也不容易出现拼写错误哦。

内容的提问来源于stack exchange,提问作者Mosab Alzouby

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:21:20