Skip to content

解决 iOS 导航栏隐藏和显示

轩辕十四
Published date:

今天在项目中遇到了隐藏 navigationbar 功能的问题,例如:从 A push到 B 页面,A 页面的 navigationbar 是隐藏的,但是 B 页面的 navigationbar 是需要显示的。

一开始我在 A 页面调用 setNavigationBarHidden(true, animated: true) 方法,在 B 页面调用 setNavigationBarHidden(false, animated: true) 方法,虽然能够达到想要的效果,但是对于项目来说是灾难性的。因为如果有多个地方出现这种情况的话,你的代码将会变得十分的杂乱臃肿。

一种好的解决方式是调用 navigationcontroller 的代理:

navigationController(_:willShow:animated:)

将这个代理放在项目控制器的基类中,在这里我是放在我的基类 BaseViewController 中。为什么这么做?因为这样可以很好的去掉冗余的代码,不用写的到处都是,我的所有控制器都是继承自 BaseViewController 的,BaseViewController 继承自 UIViewController

下面到了 Show Code 的时候了

基类实现代理方法

extension BaseViewController: UINavigationControllerDelegate {
    
    public func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
        
        /// 这里判断是否是当前代理控制器,如果是当前代理控制器的话,则是需要隐藏 navigationbar 的
        if viewController == self {
            navigationController.setNavigationBarHidden(true, animated: true)
        } else {
            /// 系统相册不能隐藏,所有就直接 return
            if navigationController.isKind(of: UIImagePickerController.self) {
                return
            }
            /// 不是当前代理控制器的话,显示真正的 navbar
            navigationController.setNavigationBarHidden(false, animated: true)
            /// 当不显示本页时,要么就 push 到下一页,要么就被 pop 了,那么就将 delegate 设置为 nil,防止出现 BAD ACCESS
            /// 之前将这段代码放在 viewDidDisappear 和 dealloc 中,这两种情况可能已经被 pop 了,self.navigationController 为 nil,这里采用手动持有 navigationController 的引用来解决
            if let delegate = navigationController.delegate, delegate === self {
                /// 如果 delegate 是自己才设置为 nil,因为 viewWillAppear 调用的比此方法较早,
                /// 其他 controller 如果设置了 delegate 就可能会被误伤
                navigationController.delegate = nil
            }
        }
    }
}

在需要隐藏 navigationbar 的地方,添加如下代码

self.navigationController?.delegate = self

这样就能解决显示/隐藏的问题了。

参考链接

Previous
闭包实现addTarget方法-面向协议编程
Next
Charles 如何对 HTTPS 进行抓包?