如何解决iOS 11中UINavigationBar高度变化导致Push动画视觉异常问题
我之前也踩过iOS 11这个专属的布局坑,这种导航栏高度跳变导致的视觉 glitch 确实挺闹心的。你说强制设置导航栏高度没用,大概率是因为iOS 11开始系统对UINavigationBar的布局逻辑做了调整,直接修改frame会被系统的自动布局机制覆盖。给你几个可行的解决思路:
改用iOS 11原生的SearchController集成方式
iOS 11引入了navigationItem.searchController属性,建议把你的UISearchController直接赋值给这个属性,而不是手动将SearchBar添加到导航栏或titleView中。系统会自动处理导航栏的高度适配,转场时能保持动画的连贯性。示例代码:let searchController = UISearchController(searchResultsController: nil) searchController.searchBar.placeholder = "搜索内容" navigationItem.searchController = searchController // 若需要push后仍显示搜索栏,设置此属性为false navigationItem.hidesSearchBarWhenScrolling = false这种方式是最推荐的,完全贴合系统布局逻辑,能从根源上避免高度不一致的问题。
统一转场前后的导航栏高度
如果项目没法改用原生集成方式,可以在执行push操作前,先让源ViewController的导航栏高度和目标ViewController保持一致:- 在目标ViewController的
viewWillAppear方法中,记录导航栏的目标高度; - 在源ViewController触发push前,先调整自身导航栏高度到目标值,再执行push操作;
- 转场完成后,按需恢复源ViewController导航栏的原有高度。
注意:调整高度时不要直接修改frame,建议通过修改导航栏的layoutMargins、添加约束,或者调用setNeedsLayout()触发系统重新布局,避免被自动布局覆盖。
- 在目标ViewController的
自定义转场动画控制器
实现UINavigationControllerDelegate的navigationController:animationControllerForOperation:fromViewController:toViewController:方法,自定义push转场动画。在动画过程中手动控制导航栏的高度变化,让它平滑过渡而非突然跳变。这种方式需要你对Core Animation有一定了解,但能完全掌控动画细节,彻底解决视觉异常。统一导航栏的自动调整行为
检查两个ViewController的导航栏设置是否一致:比如关闭prefersLargeTitles(iOS 11新增的大标题模式也会影响导航栏高度),确保navigationBar.prefersLargeTitles = false;同时确认两个页面的滚动视图内容适配设置一致(iOS 11中automaticallyAdjustsScrollViewInsets被contentInsetAdjustmentBehavior替代,统一设置可避免布局偏移)。
内容的提问来源于stack exchange,提问作者Quentin

