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
相关产品推荐
相关产品推荐

