UIKit如何实现tableview cell侧滑返回时保持高亮并跟随手势取消高亮
实现方案
这个交互是UIKit内置支持的能力,无需自定义手势监听,只需要按以下规则配置即可:
原理说明
核心逻辑是延迟cell选中状态的取消时机,跟随导航控制器的pop交互转场进度动态处理:
- 侧滑返回过程中保持cell高亮
- 转场完成(完全返回列表页)时执行取消高亮动画
- 转场取消(滑动到一半退回详情页)时保留cell选中状态
代码实现
1. 如果你使用系统UITableViewController
仅需设置一个属性即可获得默认效果:
// Swift clearsSelectionOnViewWillAppear = true
// Objective-C self.clearsSelectionOnViewWillAppear = YES;
这个属性默认就是开启状态,只要你没有手动关闭就会自带跟随侧滑取消高亮的效果。
2. 自定义UIViewController嵌套UITableView
需要自己在viewWillAppear中处理转场协调逻辑:
Swift 代码
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) guard let selectedIndexPath = tableView.indexPathForSelectedRow else { return } if let coordinator = transitionCoordinator { // 跟随转场动画执行取消选中逻辑 coordinator.animate(alongsideTransition: { context in if !context.isCancelled { self.tableView.deselectRow(at: selectedIndexPath, animated: true) } }, completion: { context in // 转场取消时恢复选中状态 if context.isCancelled { self.tableView.selectRow(at: selectedIndexPath, animated: false, scrollPosition: .none) } }) } else { // 非交互转场(比如点击返回按钮)直接取消选中 tableView.deselectRow(at: selectedIndexPath, animated: animated) } } // 点击cell的回调里不要调用deselectRow,直接执行push逻辑即可 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let detailVC = DetailViewController() // 你的传参逻辑 navigationController?.pushViewController(detailVC, animated: true) }
Objective-C 代码
- (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; NSIndexPath *selectedIndexPath = [self.tableView indexPathForSelectedRow]; if (!selectedIndexPath) return; id<UIViewControllerTransitionCoordinator> coordinator = self.transitionCoordinator; if (coordinator) { [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) { if (!context.isCancelled) { [self.tableView deselectRowAtIndexPath:selectedIndexPath animated:YES]; } } completion:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) { if (context.isCancelled) { [self.tableView selectRowAtIndexPath:selectedIndexPath animated:NO scrollPosition:UITableViewScrollPositionNone]; } }]; } else { [self.tableView deselectRowAtIndexPath:selectedIndexPath animated:animated]; } } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { DetailViewController *detailVC = [[DetailViewController alloc] init]; // 你的传参逻辑 [self.navigationController pushViewController:detailVC animated:YES]; }
注意事项
- 不要在
didSelectRowAt方法中直接调用deselectRow,否则cell会立刻取消高亮,无法跟随侧滑手势显示交互效果 - 如果自定义了
UINavigationController的delegate,确保没有拦截系统的转场协调逻辑,否则transitionCoordinator会返回空 - 该实现逻辑同样适用于
UICollectionView,仅需替换UITableView的选中/取消选中方法为UICollectionView对应的方法即可
内容的提问来源于stack exchange,提问作者qiuyang
相关产品推荐
相关产品推荐

