15

I am able to get userInterfaceStyle using TraitCollection of any view or ViewController ie. Dark or Light. But when I forced app to use Dark or light Mode, then I want to know what is the current userInterfaceStyle of iOS device irrespective of app?

I tried Traitcollection of UIScreen but still its provide userInterfaceStyle of app not device.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Raushan Kumar
  • 171
  • 1
  • 2
  • 6

3 Answers3

34

Try UIScreen.main, swift 5 example:

// OS-wide theme available on iOS 13.
@available(iOS 13.0, *)
var osTheme: UIUserInterfaceStyle {
    return UIScreen.main.traitCollection.userInterfaceStyle
}
Hammerhead
  • 1,044
  • 8
  • 19
  • 4
    Its for detecting userInterfaceStyle of app level . But when you force your app to display a particular mode ie. dark or light mode only. Then its not able to detect interfaceStyle of device. And I have also mentioned this solution in question it self – Raushan Kumar Aug 29 '19 at 09:36
  • 1
    How do you force your app to display a particular mode? For our app, we set overrideUserInterfaceStyle of key window to do that, then we use the method above to detect system theme settings, it works fine. – Hammerhead Aug 30 '19 at 02:38
  • Set UIUserInterfaceStyle key in info.plist with value Light or Dark to force app to use particular display mode then your solution will stop working – Raushan Kumar Aug 30 '19 at 07:54
  • 2
    From what i know, setting `UIUserInterfaceStyle` key in info.plist means you decide to completely opt out of dark theme, then why do you care about if os dark theme is on? are you trying to achieve something like using dark theme or not based on your app settings? If so, like I mentioned above, you can set key window's overrideUserInterfaceStyle to override app-wide theme, and use uiscreen's traitCollection for detecting os-wide theme – Hammerhead Aug 30 '19 at 08:05
  • I have an app with multiple window configured with light mode and I don't want to use this redundant code. But i want to display one view controller as per device display mode.So, I am trying to get device display mode – Raushan Kumar Aug 30 '19 at 09:54
  • typo (Objective C version): UIScreen.mainScreen.traitCollection.userInterfaceStyle – Jeff Oct 24 '19 at 00:46
  • did anyone find solution? – Berlin Aug 18 '21 at 13:15
1

In the cases where you have multiple ViewControllers or Windows where you want the interface style to be dynamic (or as in your case, locked), I would argue to use the traitCollectionDidChange(_:) callback and look at the property userInterfaceStyle. This will reflect the current state of the interface style (even if locked). Just remember that child view controllers will inherit their parent´s setting.

This way you can design your code to behave correctly depending on the current interface style being transitioned from->to. The below example will work in custom UIViewControllers as well as custom UIViews.

Example (swift 4):

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    super.traitCollectionDidChange(previousTraitCollection)
    if self.traitCollection.userInterfaceStyle != previousTraitCollection.userInterfaceStyle {
    // Your custom implementation here that is run right after the userInterfaceStyle has changed.
    }
}
Widerberg
  • 1,118
  • 1
  • 10
  • 24
0
         1. on first button click it will change to light mode
         2. on second button click it will change to dark mode
         3. on third button click it will adopt system theme (iphone/ipad)
        
        @IBAction func onBtn1Click(_ sender: Any) {
            if #available(iOS 13.0, *) {
                self.setTheme(theme: .light)
            } else {
                // Fallback on earlier versions
            }
        }
    
        @IBAction func onBtn2Click(_ sender: Any) {
        if #available(iOS 13.0, *) {
            self.setTheme(theme: .dark)
        } else {
            // Fallback on earlier versions
        }
    }

@IBAction func onBtn3Click(_ sender: Any) {
    if #available(iOS 13.0, *) {
        self.setTheme(theme: .unspecified)
    } else {
        // Fallback on earlier versions
    }
}

@available(iOS 13.0, *)
func setTheme(theme : UIUserInterfaceStyle) {
    let keyWindow = UIApplication.shared.connectedScenes
        .filter({$0.activationState == .foregroundActive})
        .compactMap({$0 as? UIWindowScene})
        .first?.windows
        .filter({$0.isKeyWindow}).first
    
    if theme == .light {
        keyWindow?.overrideUserInterfaceStyle = .light
    } else if theme == .dark {
        keyWindow?.overrideUserInterfaceStyle = .dark
    } else {
        if UIScreen.main.traitCollection.userInterfaceStyle == .dark {
            keyWindow?.overrideUserInterfaceStyle = .dark
        } else {
            keyWindow?.overrideUserInterfaceStyle = .light
        }
    }
}
Bhawin Ranpura
  • 129
  • 1
  • 8