7

I am trying to achieve reading dark mode in my app built in SwiftUI, Xcode 12 and iOS14.

I am using this key to find wether or not it's in light or dark mode: @Environment(\.colorScheme) var colorScheme

My testing device is set to dark mode, but the environment variable is reading light mode.

I have tested this removing the app, reloading XCode, and restarting my Macbook Pro.

User Interface Style is not used since this is iOS14. (SwiftUI: Dark mode not detected when testing on device)

The weird thing is, my testing device (iPhone 11 Pro) renders non-background colored views as dark as they should. So the only thing that isn't updating is the variable colorScheme itself. I am not changing that value anywhere in my app programatically.

I also checked that my info.plist is routed properly in the build settings of the target. I am using a target for the main app, and a target for a widget extension.

What am I Missing?

pawello2222
  • 46,897
  • 22
  • 145
  • 209
Jprofficial
  • 329
  • 3
  • 10
  • The `.colorScheme` reads system appearance, why do you expect it reacts on changed Info.plist? – Asperi Nov 22 '20 at 19:33
  • @Asperi I expected it to read `Dark` when it's set to `Dark` in the Info.plist. per https://stackoverflow.com/questions/56537855/is-it-possible-to-opt-out-of-dark-mode-on-ios-13?rq=1 - Clearly I misunderstood that usage. – Jprofficial Nov 22 '20 at 19:42
  • Edited the question to reflect that understanding – Jprofficial Nov 22 '20 at 19:44

3 Answers3

7

I just found out why

I am reading @Environment(\.colorScheme) var colorScheme: ColorScheme too early in the apps lifecycle.

When I open the app, I create my data class BEFORE the app had finished initializing. I was calling the @Environment(\.colorScheme) var colorScheme: ColorScheme in this data class.

I tested using @Environment(\.colorScheme) var colorScheme: ColorScheme on a view once the app finished initializing with .onAppear() and it worked as it should have

Jprofficial
  • 329
  • 3
  • 10
  • Also, using `@Environment(\.colorScheme) var colorScheme: ColorScheme` in an `@environmentobject` does not change from my testing. I had to reference it in a view and it worked properly. – Jprofficial Nov 23 '20 at 02:32
  • Very good. I observed the same behaviour using the new **SwiftUI lifecycle**. The colorScheme has to be read in the first `View` rather than the `App` struct. – Leo Apr 24 '22 at 14:30
  • YES! This is how I am handing this in `body` of my view: ```swift var body: some View { VStack { ... .onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in broughtToForeground = true // an @State property } } .onAppear { if broughtToForeground { updateColors() broughtToForeground = false } } } ``` – Mark Volkmann Jul 15 '22 at 14:52
7

In my project, I found @Environment(\.colorScheme) var colorScheme Get the color scheme of your software, not the color scheme of the system.

So when you manually change the color scheme of the software itself, @Environment(\.colorScheme) var colorScheme You can’t get the phone’s color scheme again.

Use the following code instead, it will get you the color scheme of the phone

let currentSystemScheme = UITraitCollection.current.userInterfaceStyle

It should be noted that userInterfaceStyle and colorScheme are not the same type, so you may need the following code to convert

func schemeTransform(userInterfaceStyle:UIUserInterfaceStyle) -> ColorScheme {
    if userInterfaceStyle == .light {
        return .light
    }else if userInterfaceStyle == .dark {
        return .dark
    }
    return .light}
dyeeee
  • 71
  • 1
  • 4
0

I expected it to read Dark when it's set to Dark in the Info.plist. per …

Hmm... Apple's documentation says enumerates the user setting options (see below complete snapshot):

/// The possible types of color schemes, like Dark Mode.
///
/// The color scheme enumerates the user setting options for Light or Dark Mode.
/// It also provides the light or dark options for any particular view when the
/// app wants to override the user setting.
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
public enum ColorScheme : CaseIterable {

    case light

    case dark
Asperi
  • 228,894
  • 20
  • 464
  • 690
  • Yes I'm following you, thanks for the comment. I updated my original question. The issue is that `@Environment(\.colorScheme) var colorScheme: ColorScheme` isn't updating to the devices mode. My test device is in dark mode and the app is reading light mode. – Jprofficial Nov 22 '20 at 19:52