Search code examples
iosswiftuiviewcontrolleruinavigationcontrolleruinavigationitem

Dynamically Change iOS Nav Bar Color (Dark Mode)


I'm trying to implement a toggle for dark mode in my app - this would involve toggling the nav bar color to black when the UIViewController is already visible on the screen. I'm aware of how to do this by setting

UINavigationBar.appearance().barTintColor = .black
UINavigationBar.appearance().tintColor = .white
UINavigationBar.appearance().titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
UINavigationBar.appearance().isTranslucent = false

in the AppDelegate, however, this won't work in this case as it needs to be done dynamically.

I've also tried navigationController?.navigationBar.barTintColor = UIColor.white but this doesn't work either.

UPDATE:

I think a lot of the responses were confused with the purpose of this question - this is NOT at all related to the iOS13 Dark Mode which was just released - it is an INDEPENDENT dark mode feature I want to add to my app (similar to other apps like Messenger etc which had dark mode available IN-APP before iOS 13 was released). What I need to do is dynamically update the color of the UINavigationBar AFTER it has been already displayed on the screen, the same way I can change the background color of a view by doing view.backgroundColor = .white and this will update the color in real-time on screen.


Solution

  • Achieved this by making the nav bar translucent (in AppDelegate):

    let barAppearance = UINavigationBar.appearance()
    barAppearance.titleTextAttributes = [NSAttributedString.Key.foregroundColor: appRed]
    barAppearance.setBackgroundImage(UIImage(), for: UIBarMetrics.default)
    barAppearance.shadowImage = UIImage()
    barAppearance.isTranslucent = true
    

    Next I create a view and place it behind the nav bar as follows (using SnapKit):

    let coverView = UIView() 
    cover.snp.makeConstraints {
            make in
            make.left.right.top.equalTo(self)
            make.bottom.equalTo(self.snp.top).offset(universalNumber(num: parent!.topbarHeight))
    }
    

    where the parent is my UIViewController and topBarHeight is:

    extension UIViewController {
    /**
     *  Height of status bar + navigation bar (if navigation bar exist)
     */
        var topbarHeight: CGFloat {
            return UIApplication.shared.statusBarFrame.size.height +
                (self.navigationController?.navigationBar.frame.height ?? 0.0)
        }
    }
    

    Finally, to update the color I set

    coverView.backgroundColor = universalWhite() 
    

    where

    func universalWhite() -> UIColor {
       let defaults = UserDefaults.standard
       let darkMode = defaults.bool(forKey: "darkMode")
       if darkMode {
           return .black
       } else {
           return .white
        }
     }