激活/停用UISearchController时UITableView出现位置跳转问题
解决UITableView与UISearchController动画不同步的问题
我之前也碰到过一模一样的问题!这种搜索控制器平滑动画但tableView突然跳位的生硬感,确实很影响用户体验,给你几个我亲测有效的解决思路:
1. 利用代理方法同步tableView与搜索控制器的动画
实现UISearchControllerDelegate的两个代理方法,手动控制tableView的contentInset变化,并和搜索控制器的动画时长保持一致,让两者的动画同步:
extension YourViewController: UISearchControllerDelegate { func willPresentSearchController(_ searchController: UISearchController) { // 获取当前tableView的原有顶部内边距(比如安全区域的内边距) let originalTopInset = tableView.contentInset.top // 计算搜索栏激活后需要增加的内边距 let newTopInset = originalTopInset + searchController.searchBar.frame.height UIView.animate(withDuration: 0.3) { self.tableView.contentInset = UIEdgeInsets(top: newTopInset, left: 0, bottom: self.tableView.contentInset.bottom, right: 0) self.tableView.scrollIndicatorInsets = self.tableView.contentInset } } func willDismissSearchController(_ searchController: UISearchController) { // 恢复到原来的内边距 let originalTopInset = view.safeAreaInsets.top UIView.animate(withDuration: 0.3) { self.tableView.contentInset = UIEdgeInsets(top: originalTopInset, left: 0, bottom: self.tableView.contentInset.bottom, right: 0) self.tableView.scrollIndicatorInsets = self.tableView.contentInset } } }
记得在初始化搜索控制器时设置代理:searchController.delegate = self
2. 手动管理tableView的contentInset,关闭自动调整
有时候系统自动调整contentInset会和你的约束冲突,你可以关闭自动调整,自己手动适配安全区域:
override func viewDidLoad() { super.viewDidLoad() // 关闭tableView的自动内边距调整 tableView.contentInsetAdjustmentBehavior = .never // 手动设置安全区域的内边距 let safeAreaInsets = view.safeAreaInsets tableView.contentInset = UIEdgeInsets(top: safeAreaInsets.top, left: 0, bottom: safeAreaInsets.bottom, right: 0) tableView.scrollIndicatorInsets = tableView.contentInset }
这样系统就不会在搜索控制器激活时擅自修改tableView的内边距,你可以通过上面的代理方法完全控制动画过程。
3. 检查导航栏隐藏设置
如果你的视图控制器带有导航栏,检查hidesNavigationBarDuringPresentation属性:
searchController.hidesNavigationBarDuringPresentation = false
如果这个属性设为true,搜索控制器激活时导航栏会突然隐藏,导致tableView顶部位置跳变。保持导航栏显示可以避免这个问题,如果你确实需要隐藏导航栏,那就要在导航栏隐藏的动画里同步调整tableView的位置。
额外排查点
- 检查是否在
viewWillAppear或其他生命周期方法里强行设置了tableView的contentOffset,这可能打断动画过程; - 确认tableView的顶部约束确实是连接到
safeAreaLayoutGuide.top,没有和其他视图(比如导航栏)的约束冲突。
内容的提问来源于stack exchange,提问作者A. Walker
相关产品推荐
相关产品推荐

