简体   繁体   中英

How to detect if OS X is in dark mode?

My cocoa app has to change its behaviour when run in the new OS X "dark mode".

Is there a way to detect if OS X style is set to this mode?

Don't think there's a cocoa way of detecting it yet, however you can use defaults read to check whether or not OSX is in dark mode.

defaults read -g AppleInterfaceStyle

Either returns Dark (dark mode) or returns domain pair does not exist.

EDIT:

As Ken Thomases said you can access .GlobalPreferences via NSUserDefaults, so

NSString *osxMode = [[NSUserDefaults standardUserDefaults] stringForKey:@"AppleInterfaceStyle"];

If osxMode is nil then it isn't in dark mode, but if osxMode is @"Dark" then it is in dark mode.

Swift 2 -> String ("Dark", "Light")

let appearance = NSUserDefaults.standardUserDefaults().stringForKey("AppleInterfaceStyle") ?? "Light"

Swift 3 -> Enum (Dark, Light)

enum InterfaceStyle : String {
   case Dark, Light

   init() {
      let type = UserDefaults.standard.string(forKey: "AppleInterfaceStyle") ?? "Light"
      self = InterfaceStyle(rawValue: type)!
    }
}

let currentStyle = InterfaceStyle()

You can detect this using NSAppearanceCustomization method effectiveAppearance , by checking for darkAqua .

Swift 4 example:

extension NSView {
    var isDarkMode: Bool {
        if #available(OSX 10.14, *) {
            if effectiveAppearance.name == .darkAqua {
                return true
            }
        }
        return false
    }
}

You can also wrap it in a boolean if you don't feel like dealing with enums and switch statements:

/// True if the application is in dark mode, and false otherwise
var inDarkMode: Bool {
    let mode = UserDefaults.standard.string(forKey: "AppleInterfaceStyle")
    return mode == "Dark"
}

Works on Swift 4.2

For working with the new macOS Catalina you need to combine AppleInterfaceStyle with this new value introduced AppleInterfaceStyleSwitchesAutomatically .

Here is some pseudo-code explaining how to:

theme = light //default is light
if macOS_10.15
    if UserDefaults(AppleInterfaceStyleSwitchesAutomatically) == TRUE
        if UserDefaults(AppleInterfaceStyle) == NIL
            theme = dark // is nil, means it's dark and will switch in future to light
        else
            theme = light //means it's light and will switch in future to dark
        endif
    else
        if UserDefaults(AppleInterfaceStyle) == NIL
            theme = light
        else
            theme = dark
        endif
    endif
else if macOS_10.14
    if UserDefaults(AppleInterfaceStyle) == NIL
        theme = light
    else
        theme = dark
    endif
endif

You can check a macOS sample app here: https://github.com/ruiaureliano/macOS-Appearance .

(Disclaimer: I am the author of this sample app.)

I would check against all dark appearances like so

extension NSView {

    var hasDarkAppearance: Bool {
        if #available(OSX 10.14, *) {
            switch effectiveAppearance.name {
            case .darkAqua, .vibrantDark, .accessibilityHighContrastDarkAqua, .accessibilityHighContrastVibrantDark:
                return true
            default:
                return false
            }
        } else {
            switch effectiveAppearance.name {
            case .vibrantDark:
                return true
            default:
                return false
            }
        }
    }
}

This works:

if #available(OSX 10.14, *) {
    inputTextView.textColor = (NSApp.effectiveAppearance.name == NSAppearance.Name.darkAqua ? NSColor.white : NSColor.black)
}

2020 | SWIFT 5.1:

WAY 1:

@Environment(\.colorScheme) var scheme

WAY 2:

doesn't update swiftUI in case of theme change. Need to realize additional logic for view upd:

#available(OSX 10.14, *)
static private var isLight: Bool { NSApp.effectiveAppearance.name == NSAppearance.Name.aqua }

#available(OSX 10.14, *)
static private var isDark: Bool { NSApp.effectiveAppearance.name == NSAppearance.Name.darkAqua }

This isn't a complete answer to the question because the questioner doesn't say what their use case is. If they want completely different behaviour of their app, the below behaviour doesn't work. However, if they only want to change the colour of some custom view, this is the Apple blessed way .

The thing to do is to stop using absolute colours and start using semantic colours. This means defining a "colour set" for each colour you want to use in the assets catalog. Having defined your colour set, in the inspector, set the device to "Mac" and the appearance to "Any, Light, Dark". You will then get three colour wells, "any" is for legacy operating systems that do not support dark mode, "light" and "dark" should be obvious.

Here is an example:

定义支持暗模式的颜色集

This defines a colour that will be white in dark mode and black in light mode or on legacy operating systems.

Once you have defined a colour set, you can retrieve the colour in your draw(_ dirtyRect:) as follows:

let strokeColour = NSColor(named: NSColor.Name("gridColour")) ?? NSColor.black

In the above, I default to black if the colour set does not exist to deal with the optional type of NSColor(named:) .

The only safe way to check for dark mode is to use the following:

let viewUsesDarkMode: Bool
if #available(OSX 10.14, *) {
    viewUsesDarkMode = view.effectiveAppearance.bestMatch(from: [.aqua, .darkAqua]) == .darkAqua
} else {
    viewUsesDarkMode = false
}

This is the only solution that works in all cases. Whether you have views with mixed appearances, or if you allow your app to use a different appearance than the system default, or if you configure your system to use the high contrast appearances.

Take a look at NSAppearance.Name (in Swift speak) - there are variants:

.darkAqua

.accessibilityHighContrastDarkAqua

.accessibilityHighContrastVibrantDark

My cocoa app has to change its behaviour when run in the new OS X "dark mode".

Is there a way to detect if OS X style is set to this mode?

 let darkMode = UserDefaults.standard.string(forKey: "AppleInterfaceStyle")

if darkMode == "Dark" {
// dark theme
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM