Swift4:如何解决UITableViewController中reloadData与deselectRow动画异常?
解决UITableView reloadData与deselectRow动画冲突的问题
这个问题我之前也碰到过!在viewWillAppear里同时处理reloadData和deselectRow的动画确实容易踩坑——reloadData会直接重置表格的所有状态,包括选中状态,要么导致取消选中的动画被打断,要么因为选中状态丢失根本触发不了正常动画,系统默认的fade动画时长也确实偏短。给你几个靠谱的解决方案:
方案一:先保存选中状态,再恢复并自定义动画
核心思路是先把选中行记录下来,刷新表格后恢复选中状态,再用自定义时长的动画来执行取消选中:
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) // 提前保存当前选中的行 let selectedIndexPath = tableView.indexPathForSelectedRow // 执行表格刷新 tableView.reloadData() // 如果之前有选中的行,先恢复选中(无动画),再执行自定义时长的取消选中动画 if let indexPath = selectedIndexPath { tableView.selectRow(at: indexPath, animated: false, scrollPosition: .none) // 这里可以自定义动画时长,比如0.3秒(系统默认fade是0.2秒左右) UIView.animate(withDuration: 0.3, animations: { self.tableView.deselectRow(at: indexPath, animated: false) }) } }
方案二:用performBatchUpdates协调刷新与动画
performBatchUpdates会把表格刷新操作放到事务里执行,完成后再触发取消选中的动画,避免状态冲突:
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) let selectedIndexPath = tableView.indexPathForSelectedRow // 用批量更新包裹刷新操作,确保刷新完成后再处理动画 tableView.performBatchUpdates({ self.tableView.reloadData() }, completion: { [weak self] _ in guard let self = self, let indexPath = selectedIndexPath else { return } // 这里可以选择用系统动画,或者同样用UIView.animate自定义时长 UIView.animate(withDuration: 0.3) { self.tableView.deselectRow(at: indexPath, animated: false) } }) }
方案三:拆分操作到viewDidAppear(适合对延迟不敏感的场景)
如果允许取消选中的动画稍微延迟一点,可以把动画逻辑放到viewDidAppear里,确保表格已经完全刷新并展示:
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) // 在viewWillAppear里只做刷新 tableView.reloadData() } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) // 视图完全展示后执行取消选中的自定义动画 if let indexPath = tableView.indexPathForSelectedRow { UIView.animate(withDuration: 0.3) { self.tableView.deselectRow(at: indexPath, animated: false) } } }
注意事项
- 自定义动画时,一定要把
deselectRow的animated参数设为false,否则系统会叠加两层动画,导致效果混乱。 - 如果你的表格cell有自定义的选中样式,要确保在
cellForRowAt里正确处理选中状态的恢复,避免样式异常。
内容的提问来源于stack exchange,提问作者Tarou
相关产品推荐
相关产品推荐

