【问题标题】:How to detect if OS X is in dark mode?如何检测 OS X 是否处于暗模式?
【发布时间】:2014-10-02 03:28:21
【问题描述】:

我的 cocoa 应用在新的 OS X“黑暗模式”下运行时必须改变其行为。

有没有办法检测 OS X 样式是否设置为此模式?

【问题讨论】:

  • 在黑暗中刺伤 - 您是否尝试过收听 NSScreenColorSpaceDidChangeNotification 或检查 NSScreen colorSpace 属性。目前在 Mav 上,所以无法查看。

标签: macos cocoa themes


【解决方案1】:

检查暗模式的唯一安全方法是使用以下方法:

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

这是唯一适用于所有情况的解决方案。无论您的视图具有混合外观,还是您允许应用使用不同于系统默认外观的外观,或者您将系统配置为使用高对比度外观。

【讨论】:

    【解决方案2】:

    要使用新的 macOS Catalina,您需要将 AppleInterfaceStyle 与引入的新值 AppleInterfaceStyleSwitchesAutomatically 结合起来。

    这里有一些伪代码解释如何:

    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
    

    您可以在此处查看 macOS 示例应用程序:https://github.com/ruiaureliano/macOS-Appearance。

    (免责声明:我是此示例应用的作者。)

    【讨论】:

      【解决方案3】:

      这不是问题的完整答案,因为提问者没有说出他们的用例是什么。如果他们想要他们的应用程序完全不同的行为,则以下行为不起作用。但是,如果他们只想更改某些自定义视图的颜色,这是the Apple blessed way。

      要做的是停止使用绝对颜色并开始使用语义颜色。这意味着为要在资产目录中使用的每种颜色定义一个“颜色集”。定义好颜色集后,在检查器中将设备设置为“Mac”,外观设置为“Any, Light, Dark”。然后,您将获得三个颜色孔,“any”用于不支持暗模式的旧版操作系统,“light”和“dark”应该很明显。

      这是一个例子:

      这定义了一种颜色,在深色模式下为白色,在浅色模式或旧操作系统上为黑色。

      一旦定义了颜色集,您就可以在draw(_ dirtyRect:) 中检索颜色,如下所示:

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

      在上面,如果颜色集不存在我默认为黑色来处理NSColor(named:)的可选类型。

      【讨论】:

        【解决方案4】:

        2020 | SWIFT 5.1:

        由于某种原因没有实时更新,但仍然可以根据需要工作(可能在其他地方出现问题,与此代码无关):

        检查浅色主题:

        #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 }
        
        

        【讨论】:

        • 只需为AppleInterfaceThemeChangedNotification 分布式通知添加一个观察者,然后从那里开始。
        【解决方案5】:

        我会检查所有像这样的黑暗外观

        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
                    }
                }
            }
        }
        

        【讨论】:

          【解决方案6】:

          看看 NSAppearance.Name(斯威夫特语)—— 有变种:

          .darkAqua

          .accessibilityHighContrastDarkAqua

          .accessibilityHighContrastVibrantDark

          【讨论】:

            【解决方案7】:

            这行得通:

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

            【讨论】:

              【解决方案8】:

              您可以使用NSAppearanceCustomization 方法effectiveAppearance 检测到这一点,方法是检查darkAqua。

              Swift 4 示例:

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

              【讨论】:

              • 我正在使用[NSAppearance.Name.darkAqua, NSAppearance.Name.vibrantDark].contains(effectiveAppearance.name) 来检查两个黑暗的外观
              【解决方案9】:

              如果您不想处理枚举和 switch 语句,也可以将其包装在布尔值中:

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

              适用于 Swift 4.2

              【讨论】:

                【解决方案10】:

                Swift 2 -> 字符串(“黑暗”、“光明”)

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

                Swift 3 -> 枚举(暗、亮)

                enum InterfaceStyle : String {
                   case Dark, Light
                
                   init() {
                      let type = UserDefaults.standard.string(forKey: "AppleInterfaceStyle") ?? "Light"
                      self = InterfaceStyle(rawValue: type)!
                    }
                }
                
                let currentStyle = InterfaceStyle()
                

                【讨论】:

                • 很好,我不知道枚举可以有init() 方法!
                【解决方案11】:

                目前还没有可可检测方式,但是您可以使用defaults read 来检查 OSX 是否处于暗模式。

                defaults read -g AppleInterfaceStyle
                

                要么返回Dark(暗模式)要么返回域对不存在。

                编辑:

                正如 Ken Thomases 所说,您可以通过 NSUserDefaults 访问 .GlobalPreferences,所以

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

                如果 osxMode 为 nil 则不处于暗模式,但如果 osxMode 为 @"Dark" 则处于暗模式。

                【讨论】:

                • defaults 命令只是CFPreferences API 的包装,NSUserDefaults 也是如此。因此,您可以使用其中任何一个 API,而不是调用 defaults。
                • @houbysoft 使用KVO
                • 不适用于 Catalina:“(kCFPreferencesAnyApplication, AppleInterfaceStyle) 的域/默认对不存在”
                • @bas “不存在”大概意思是“轻模式”。
                • 我可以确认(在 Catalina 上),如果处于暗模式,则 defaults read -g AppleInterfaceStyle 返回“暗”,否则返回“(kCFPreferencesAnyApplication, AppleInterfaceStyle) 的域/默认对不存在”。很不直观:)
                猜你喜欢
                • 2019-09-05
                • 1970-01-01
                • 2021-03-25
                • 2018-11-23
                • 2022-12-05
                • 2021-08-16
                • 2020-05-09
                • 2010-10-24
                • 2011-08-13
                相关资源
                最近更新 更多