Swift 5:通过扩展无法设置UINavigationController大标题
嘿,这个问题其实是踩了一个很容易忽略的小坑——你搞混了UINavigationController实例里navigationController属性的含义!
为什么扩展没生效?
你写的扩展是给UINavigationController本身添加的方法,当你在这个方法里调用navigationController?时,你其实是在问这个导航控制器自己的父导航控制器是谁。但导航控制器本身就是顶层的导航容器,它的navigationController属性永远是nil!所以那行关键的navigationController?.navigationBar.prefersLargeTitles = true相当于完全没执行,自然看不到效果。
而你直接在ViewController的viewDidLoad里写navigationController?.navigationBar...时,这里的navigationController是当前ViewController所属的导航控制器(也就是你要配置的那个),它是有值的,所以代码能正常工作。
另外还有一个小问题:你在扩展里设置的navigationItem.title是导航控制器自己的导航项,不是你当前显示的子控制器的,就算前面的代码生效了,标题也不会显示在你期望的位置。
修复后的扩展代码
我们需要把扩展里的错误引用修正,直接操作导航控制器本身,同时针对当前顶部的子控制器设置标题:
extension UINavigationController { func configureLargeTitle(with title: String) { // 直接操作当前导航控制器的导航栏,开启大标题 navigationBar.prefersLargeTitles = true // 给当前显示的子控制器设置标题和大标题显示模式 topViewController?.navigationItem.title = title topViewController?.navigationItem.largeTitleDisplayMode = .automatic } }
更合适的写法(可选)
如果你只是想给单个子控制器配置大标题,其实给UIViewController写扩展会更直观,这样在子控制器里调用起来更自然:
extension UIViewController { func setupLargeTitle(with title: String) { // 拿到当前控制器所属的导航控制器,开启大标题 navigationController?.navigationBar.prefersLargeTitles = true // 设置当前控制器自己的导航项 navigationItem.title = title navigationItem.largeTitleDisplayMode = .automatic } }
调用的时候直接在子控制器的viewDidLoad里写:
setupLargeTitle(with: "我的页面标题")
总结
核心问题就是你在UINavigationController的扩展里错误地使用了navigationController?(这个属性对它自己来说是nil),导致关键的配置代码没执行。修正后就能正常开启大标题效果啦!
内容的提问来源于stack exchange,提问作者David Henry

