How to change app theme (Light/Dark) programmatically in swift 5

Viewed 4597

I have an app with up to 10 screens and in the settings screen, I have a toggle to switch between dark/light mode. I want to change the complete app theme on that toggle.

Currently, the app theme change when I change the theme in iOS default settings. But I want the same behavior to happen for my app only.

What I figure out till now is to set a theme variable in the user default and use this code conditional on each view controller

    view.overrideUserInterfaceStyle = // .dark // .light

I don't want to use any third party library.

2 Answers

In your app delegate didFinishLaunchingWithOptions read the preference from shared defaults and do something like this:

UIApplication.shared.keyWindow.overrideUserInterfaceStyle = preference == "dark" ? .dark : .light

In your Settings view controller do the same when the user changes the preference.

Setting the override on your window should take care of all view controllers.

Here's how i have done the same approach on similar kind of use case. I have created an extension for AppDelegate like below:

extension AppDelegate {
    func overrideApplicationThemeStyle() {
        if #available(iOS 13.0, *) {
            ....
            // Retrieve your NSUserDefaults value here
            ....
            UIApplication.shared.keyWindow?.overrideUserInterfaceStyle = yourUserDefaultsValue ? .dark : .light
        } else {
            // Fallback on earlier versions
        }
    }
}

And, my theme change is device specific. So, i have created one boolean instance in NSUserDefaults to keep the toggle changes. And, whenever the toggle changes i will call the method:

@IBAction func changeApplicationTheme() {
    ....
    // Your code to store the changes in NSUserDefaults
    ....
    AppDelegate.shared.overrideApplicationStyle()
}

And, more importantly this theme has been introduced from iOS 13 onwards the best place to call it from func sceneDidBecomeActive(_ scene: UIScene) whenever app launches and would like to apply the user selected theme.

func sceneDidBecomeActive(_ scene: UIScene) {
    AppDelegate.shared.overrideApplicationStyle()
}
Related