优化iOS 11异步操作下leadingSwipeActions的视觉交互效果
解决UITableViewCell右滑异步操作的加载状态控制问题
咱们先明确要实现的核心效果:
- 右滑单元格触发异步操作时,立刻显示加载指示器
- 操作进行期间:
- 隐藏单元格内的文本标签
- 让单元格保持“内联”状态(不会停留在滑动展开的菜单界面)
- 禁止用户再次滑动该单元格
- 持续展示加载指示器直到操作完成
第一步:准备必要的状态跟踪和单元格配置
首先,我们需要一个集合来跟踪正在执行异步操作的单元格索引,避免重复触发;同时要给自定义的UITableViewCell添加加载指示器控件。
1. 自定义UITableViewCell子类
class CustomTableViewCell: UITableViewCell { // 你的原有内容标签 @IBOutlet weak var contentLabel: UILabel! // 添加加载指示器控件 @IBOutlet weak var activityIndicator: UIActivityIndicatorView! override func awakeFromNib() { super.awakeFromNib() // 默认隐藏加载指示器 activityIndicator.isHidden = true } // 统一切换加载状态的方法 func setLoading(_ isLoading: Bool) { contentLabel.isHidden = isLoading isLoading ? activityIndicator.startAnimating() : activityIndicator.stopAnimating() activityIndicator.isHidden = !isLoading } }
2. 在ViewController中添加状态跟踪变量
class YourViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { // 用集合跟踪正在加载的indexPath,避免重复触发操作 private var loadingIndexPaths = Set<IndexPath>() // 你的tableView实例 @IBOutlet weak var tableView: UITableView! // ... 其他原有代码(数据源、代理方法等) ... }
第二步:完善滑动动作配置和异步操作逻辑
接下来修改你已有的leadingSwipeActionsConfigurationForRowAt方法,加入状态判断和加载控制:
override func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { // 如果当前单元格正在加载,直接返回nil,禁止用户再次滑动 guard !loadingIndexPaths.contains(indexPath) else { return nil } let action = UIContextualAction(style: .normal, title: "执行操作") { [weak self] (action, view, completionHandler) in guard let self = self else { completionHandler(false) return } // 标记当前单元格为加载中 self.loadingIndexPaths.insert(indexPath) // 立即更新单元格状态,显示加载指示器 if let cell = tableView.cellForRow(at: indexPath) as? CustomTableViewCell { cell.setLoading(true) } // 调用completionHandler让单元格立刻回到内联状态 completionHandler(true) // 替换成你的真实异步业务逻辑(这里用延迟模拟) DispatchQueue.global().asyncAfter(deadline: .now() + 3) { DispatchQueue.main.async { // 操作完成后移除加载标记 self.loadingIndexPaths.remove(indexPath) // 恢复单元格原始状态 if let cell = tableView.cellForRow(at: indexPath) as? CustomTableViewCell { cell.setLoading(false) } // 可选:如果需要刷新数据,可调用 tableView.reloadRows(at: [indexPath], with: .automatic) } } } // 可以给滑动动作设置样式,比如背景色 action.backgroundColor = .systemBlue return UISwipeActionsConfiguration(actions: [action]) }
关键逻辑说明
- 状态防重复:用
Set<IndexPath>记录正在加载的单元格,确保同一单元格不会被重复触发操作 - 禁止重复滑动:创建滑动动作前先检查加载状态,存在则返回
nil,用户无法再次滑动该单元格 - 立即回到内联:触发操作后立刻调用
completionHandler(true),让单元格自动收起滑动菜单,保持内联展示 - 统一状态切换:通过自定义的
setLoading(_:)方法,一键控制标签隐藏和加载指示器的显示/动画
这样就能完美实现你需要的所有效果啦!
内容的提问来源于stack exchange,提问作者KevinSkyba
相关产品推荐
相关产品推荐

