求助:iOS 13导航栏大/小标题切换不流畅,过渡效果异常
解决iOS13下导航栏大/小标题切换不流畅的问题
我之前也碰到过这个iOS13特有的导航栏过渡卡顿问题,你的思路其实有道理,但修改prefersLargeTitles的时机和方式不符合iOS13的布局逻辑,导致了动画冲突。
问题根源
iOS13对导航栏的布局时机做了优化调整,当你在viewWillDisappear里修改导航栏的全局prefersLargeTitles属性时,页面过渡动画已经启动,这时候修改会触发导航栏的强制重布局,和正在进行的过渡动画产生冲突,所以出现了不流畅的现象。而iOS12的布局调度逻辑和iOS13不同,所以你的原有代码能正常工作。
最优解决方案:利用navigationItem的独立配置
苹果设计导航栏时,本来就支持每个视图控制器独立控制大标题的显示模式,不需要手动修改导航栏的全局属性。我们可以通过设置每个VC的navigationItem.largeTitleDisplayMode来让系统自动处理过渡动画,这种方式在iOS12和iOS13上都能流畅运行。
列表页(首页)代码:
class ListViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // 开启全局大标题支持 navigationController?.navigationBar.prefersLargeTitles = true // 当前页面始终显示大标题 navigationItem.largeTitleDisplayMode = .always } }
详情页代码:
class DetailsViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // 当前页面不显示大标题(自动切换为小标题) navigationItem.largeTitleDisplayMode = .never } }
为什么这个方法有效?
largeTitleDisplayMode是每个视图控制器的独立配置,系统会在页面过渡的合适时机(动画开始前)自动调整导航栏的显示状态,避免了手动修改全局属性带来的布局冲突,完美解决iOS13的过渡卡顿问题。
如果一定要保留原有逻辑的替代方案
如果你因为某些原因必须手动修改prefersLargeTitles,可以调整修改时机,比如在viewWillAppear中恢复设置,而不是willMove(to parent:),同时配合动画块确保过渡流畅:
列表页修改:
override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) // 在动画开始前修改属性,配合动画块 UIView.animate(withDuration: animated ? 0.3 : 0) { self.navigationController?.navigationBar.prefersLargeTitles = false } } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) UIView.animate(withDuration: animated ? 0.3 : 0) { self.navigationController?.navigationBar.prefersLargeTitles = true } }
详情页移除willMove(to parent:)中的代码,不需要额外处理
不过还是更推荐第一种方案,这是苹果官方设计的标准用法,兼容性和稳定性更好。
内容的提问来源于stack exchange,提问作者Mohmmad S
相关产品推荐
相关产品推荐

