Swift中present弹出的LogOutViewController导航栏按钮不显示的原因与解决
问题根因
这个导航栏按钮不显示的核心原因,是对navigationItem和UINavigationController的绑定机制认知偏差:
- 每个UIViewController自带的
navigationItem配置对象,上面设置的左右按钮、标题等内容,只有当当前控制器是UINavigationController导航栈的栈顶成员时,才会被系统导航栏读取并渲染 - 你从
LoginViewController中直接present的LogOutViewController是没有任何容器包裹的裸控制器,它的navigationController属性为nil,根本不存在对应的系统导航栏去读取你在viewDidLoad里配置的左侧退出按钮,自然无法显示 - 之前测试“普通VC直接present LogOutViewController按钮正常”的场景,本质是那个路径下的
LogOutViewController实际处于导航栈的渲染范围内(大概率是测试时复用了根导航栈中已有的LogOutViewController实例,而非从LoginVC路径新建的裸实例),所以能正常显示按钮。
修复方案
方案1(推荐,符合iOS开发规范)
不要直接present裸的LogOutViewController,在弹出前先将它包装为UINavigationController的根控制器,复用系统导航栏的渲染逻辑:
修改LoginViewController的登录成功回调代码:
@IBAction func loginButn(_ sender: Any) { guard let email = emailTf.text, let password = passwordTf.text else { print("form is not valid") return } Auth.auth().signIn(withEmail: email, password: password, completion: { (user, error) in if error != nil{ print("login adding error: \(String(describing: error))" as Any) return } print("login sucessfully") let logOutVC = self.storyboard?.instantiateViewController(withIdentifier: "LogOutViewController") as! LogOutViewController // 新增:将LogOutVC包装到导航容器中 let navContainer = UINavigationController(rootViewController: logOutVC) // 修改:弹出导航容器而非裸的LogOutVC self.present(navContainer, animated: true, completion: nil) }) }
调整后无论从哪个路径弹出LogOutViewController,它都会被对应的导航栏管理,之前配置的左侧退出按钮会正常渲染。
方案2(不推荐)
如果不需要系统导航栏的交互能力,也可以在LogOutViewController的视图层级里手动添加UINavigationBar控件,手动把退出按钮绑定到这个自定义导航栏上。但这种方式需要手动处理SafeArea适配、导航栏布局、点击响应,开发成本高,也不符合iOS系统的交互一致性要求。
排查补丁
如果完成上述调整后按钮依然不显示,可以从两个方向排查:
- 检查
LogOutViewController的生命周期方法(比如viewWillAppear)中,是否存在主动隐藏导航栏的代码:navigationController?.setNavigationBarHidden(true, animated: false),如果存在需要把隐藏状态改为false - 检查导航栏的
tintColor设置,确认按钮颜色没有和导航栏背景色一致,导致视觉上看不见按钮
内容的提问来源于stack exchange,提问作者Swift
相关产品推荐
相关产品推荐

