iOS 11中TableView跳转UIView后导航栏下方出现异常间隙问题
问题原因分析
这个问题我之前也碰到过,核心原因是UISearchBar作为导航栏titleView时,会拉高导航栏的默认高度,但控制器转场过程中,导航栏的高度没有及时在新控制器中重置为默认值:
- 新控制器加载时,布局(尤其是滚动视图的安全区内边距)还是基于被拉高的导航栏高度计算,所以导航栏下方会出现异常间隙;
- 返回原控制器时,TableView的
contentOffset会因为导航栏高度的突然变化,被系统错误调整,出现偏移异常。
至于新工程无法复现,大概率是因为新工程的默认配置(比如导航栏属性、TableView的内边距调整策略)和你的现有工程不一致,比如现有工程可能自定义了导航栏布局,或者开启了某些影响高度计算的隐藏设置。
解决思路与代码方案
下面是几个经过验证的解决方法,你可以根据工程情况选择:
方法1:转场时临时切换导航栏的titleView
在嵌入TableView的原控制器中,利用生命周期方法在转场前移除SearchBar,返回时再恢复,让导航栏在push过程中保持默认高度:
private let searchBar = UISearchBar() override func viewDidLoad() { super.viewDidLoad() searchBar.delegate = self navigationItem.titleView = searchBar } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) // 转场前替换成空视图,强制导航栏回到默认高度 navigationItem.titleView = UIView(frame: .zero) } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) // 返回时重新设置SearchBar navigationItem.titleView = searchBar // 可选:如果返回时TableView仍有偏移,手动修正 let correctTopOffset = -tableView.adjustedContentInset.top if tableView.contentOffset.y != correctTopOffset { tableView.contentOffset = CGPoint(x: 0, y: correctTopOffset) } }
方法2:在新控制器中强制重置导航栏布局
如果不想修改原控制器的代码,可以在被push的新控制器中,强制让导航栏回到默认布局状态:
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) // 清空titleView并强制刷新导航栏布局 navigationItem.titleView = nil navigationController?.navigationBar.setNeedsLayout() navigationController?.navigationBar.layoutIfNeeded() // 确保新控制器的滚动视图内边距正确适配安全区 scrollView.contentInsetAdjustmentBehavior = .automatic }
方法3:手动修正TableView的偏移问题
如果返回原控制器时TableView偏移异常,可以在原控制器的布局方法中手动修正:
override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() let expectedTopInset = tableView.adjustedContentInset.top // 确保TableView的contentOffset不会被系统错误拉偏 if tableView.contentOffset.y < -expectedTopInset { tableView.contentOffset = CGPoint(x: 0, y: -expectedTopInset) } }
额外排查点
如果以上方法无效,建议检查这些细节:
- 导航栏是否开启了
prefersLargeTitles,如果原控制器开启而新控制器关闭,也可能导致高度过渡异常; - 工程中是否有自定义的
UINavigationBar子类,或者全局的导航栏外观设置,这些可能干扰默认的高度计算; - 两个控制器的滚动视图约束是否真的正确对齐安全区(可以通过Xcode调试模式查看视图层级,确认滚动视图的top约束是连到安全区而非导航栏底部)。
内容的提问来源于stack exchange,提问作者Lee Jarvis
相关产品推荐
相关产品推荐

