Swift开发:如何将TableView单元格中设置过属性的字符串重置为原文本
问题描述
我有一个TableView,其每个单元格中都有一个UISwitch控件,开启该控件后会修改当前行的label内容。
我的修改逻辑如下:
@IBAction func completedTask(_ sender: UISwitch) { //Getting original taskLabel let initalLabel = taskLabel.text //Modifying the string to have a line through it. Storing it in variable attributeString let attributeString: NSMutableAttributedString = NSMutableAttributedString(string: taskLabel.text!) attributeString.addAttribute(NSAttributedString.Key.strikethroughStyle, value: 2, range: NSMakeRange(0, attributeString.length)) if sender.isOn{ print("attributed Label --> ",attributeString) taskLabel.textColor = UIColor.red taskLabel.attributedText = attributeString }else{ print("initial Label --> ",initalLabel!) taskLabel.text = initalLabel taskLabel.textColor = UIColor.black } }
目前我遇到的问题是无法将label重置回原始字符串状态。我做了演示,同时添加了多条打印语句辅助调试,可以看到initialLabel变量存储了正确的单元格值,但不知道为什么赋值不生效。
演示效果如下:
请问为什么taskLabel无法正确显示原始字符串?
原因与解决方案
直接原因
你在重置样式时没有先清空UILabel的attributedText属性。当你给UILabel设置过富文本之后,直接赋值text属性不会自动清除之前的富文本属性,残留的删除线属性会导致文本样式不刷新。
临时修复方案
在else分支中先将attributedText置为nil,再赋值普通文本即可解决当前点击不生效的问题:
@IBAction func completedTask(_ sender: UISwitch) { let originalText = taskLabel.text ?? "" let attributeString: NSMutableAttributedString = NSMutableAttributedString(string: originalText) attributeString.addAttribute(NSAttributedString.Key.strikethroughStyle, value: 2, range: NSMakeRange(0, attributeString.length)) if sender.isOn { taskLabel.textColor = .red taskLabel.attributedText = attributeString } else { // 先清空富文本,清除残留属性 taskLabel.attributedText = nil taskLabel.text = originalText taskLabel.textColor = .black } }
彻底解决方案
你当前的逻辑存在本质缺陷:TableView的单元格是复用的,你把状态和原始文本存在UI控件上,单元格滚动出屏幕再滚回时状态会错乱。你需要把状态存储在数据源中,具体实现如下:
- 定义任务模型,存储原始文本和完成状态
struct Task { let title: String var isCompleted: Bool } // 控制器内维护数据源数组 var tasks: [Task] = []
- 在
cellForRowAt方法中根据数据源状态设置UI
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "TaskCell", for: indexPath) as! TaskCell let task = tasks[indexPath.row] // 给单元格绑定当前行索引,方便点击开关时定位数据源 cell.currentIndex = indexPath.row cell.taskSwitch.isOn = task.isCompleted if task.isCompleted { let attributeString = NSMutableAttributedString(string: task.title) attributeString.addAttribute(.strikethroughStyle, value: 2, range: NSRange(location: 0, length: attributeString.length)) cell.taskLabel.attributedText = attributeString cell.taskLabel.textColor = .red } else { cell.taskLabel.attributedText = nil cell.taskLabel.text = task.title cell.taskLabel.textColor = .black } return cell }
- 开关点击时先修改数据源,再刷新对应行
在单元格子类中定义回调闭包,点击开关时通知控制器修改数据源:
// 单元格子类代码 class TaskCell: UITableViewCell { @IBOutlet weak var taskLabel: UILabel! @IBOutlet weak var taskSwitch: UISwitch! var currentIndex: Int = 0 var switchStateChanged: ((Bool, Int) -> Void)? @IBAction func completedTask(_ sender: UISwitch) { switchStateChanged?(sender.isOn, currentIndex) } }
控制器中绑定回调,刷新对应行:
// cellForRowAt中添加回调绑定 cell.switchStateChanged = { [weak self] isOn, index in self?.tasks[index].isCompleted = isOn self?.tableView.reloadRows(at: [IndexPath(row: index, section: 0)], with: .none) }
内容的提问来源于stack exchange,提问作者user17312483
相关产品推荐
相关产品推荐

