如何在macOS 10.14上检测到暗模式?

时间:2018-08-03 11:57:54

标签: objective-c macos appearance macos-mojave

在macOS 10.14中,用户可以选择采用系统范围的亮或暗外观,我需要根据当前模式手动调整一些颜色。

6 个答案:

答案 0 :(得分:14)

由于您通常通过effectiveAppearance获得的实际外观对象是复合外观,因此直接询问其名称可能不是一个可靠的解决方案。

请求currentAppearance通常也不是一个好主意,因为视图可能已显式设置为亮模式,或者您想知道{{1}之外的视图是亮还是暗},在模式切换后您可能会得到不正确的结果。

我想出的解决方案如下:

drawRect:

您将像BOOL appearanceIsDark(NSAppearance * appearance) { if (@available(macOS 10.14, *)) { NSAppearanceName basicAppearance = [appearance bestMatchFromAppearancesWithNames:@[ NSAppearanceNameAqua, NSAppearanceNameDarkAqua ]]; return [basicAppearance isEqualToString:NSAppearanceNameDarkAqua]; } else { return NO; } } 那样使用它,因为如果您明确设置appearanceIsDark(someView.effectiveAppearance),则特定视图的外观可能会与另一个视图的外观不同。

您还可以在someView.appearance上创建一个类别,并添加一个NSAppearance方法以获得- (BOOL)isDark(最好选择一个Apple将来不太可能使用的名称,例如添加供应商前缀)。

答案 1 :(得分:12)

我已使用当前外观检查系统是否为10.14

+ (BOOL)isDarkMode {
    NSAppearance *appearance = NSAppearance.currentAppearance;
    if (@available(*, macOS 10.14)) {
        return appearance.name == NSAppearanceNameDarkAqua;
    }

    return NO;
}

要检测视图中模式的变化,方法是:

- (void)updateLayer;
- (void)drawRect:(NSRect)dirtyRect;
- (void)layout;
- (void)updateConstraints;

要检测视图控制器中模式的变化,方法是:

- (void)updateViewConstraints;
- (void)viewWillLayout;
- (void)viewDidLayout;

使用通知:

// Monitor menu/dock theme changes...
[NSDistributedNotificationCenter.defaultCenter addObserver:self selector:@selector(themeChanged:) name:@"AppleInterfaceThemeChangedNotification" object: nil];

-(void)themeChanged:(NSNotification *) notification {
    NSLog (@"%@", notification);
}

有关更多信息,Dark Mode Documentation

答案 2 :(得分:4)

雨燕4

func isDarkMode(view: NSView?) -> Bool {
    if #available(OSX 10.14, *) {
        if let appearance = view?.effectiveAppearance ?? NSAppearance.current {
            return (appearance.name == .darkAqua)
        }
    }
    return false
}

更新:

func isDarkMode(view: NSView) -> Bool {
    if #available(OSX 10.14, *) {
        return view.effectiveAppearance.bestMatch(from: [.darkAqua, .aqua]) == .darkAqua
    }
    return false
}

答案 3 :(得分:1)

一个视图实际上有8个可能的appearances,其中4个是普通使用的。也就是说,

  1. NSAppearanceNameAqua灯光模式,
  2. NSAppearanceNameDarkAqua黑暗模式,
  3. NSAppearanceNameAccessibilityHighContrastAqua增强对比度的灯光模式(通过辅助功能设置),
  4. NSAppearanceNameAccessibilityHighContrastDarkAqua暗模式,对比度增强。

直接比较

appearance.name == NSAppearanceNameDarkAqua;

如果

对比度增强,可能无法检测到黑暗模式。因此,请始终使用bestMatchFromAppearancesWithNames

最好考虑高对比度的外观,以实现更好的可访问性。

答案 4 :(得分:0)

要了解 app 外观是否为深色,请使用下一个代码:

+ (BOOL)isDarkMode {
    NSString *interfaceStyle = [NSUserDefaults.standardUserDefaults valueForKey:@"AppleInterfaceStyle"];
    return [interfaceStyle isEqualToString:@"Dark"];
}

答案 5 :(得分:0)

对我来说,如果我想要一个全局状态,而不是每个视图,并且我没有访问该视图的权限,并且希望收到更新的通知,这些答案都不起作用。

解决方案是在主线程中请求NSApp.effectiveAppearance,或者至少在当前回调方法返回系统后

因此,首先我必须按照SaúlMoreno Abril的指示进行注册,并使用类似的代码

[NSDistributedNotificationCenter.defaultCenter addObserver:self selector:@selector(themeChanged:) name:@"AppleInterfaceThemeChangedNotification" object: nil];

然后在回调方法上写类似

-(void)themeChanged:(NSNotification *) notification {
    [self performSelectorOnMainThread:@selector(themeChangedOnMainThread) withObject:nil waitUntilDone:false];
}

,然后是实际代码:

- (void) themeChangedOnMainThread {
    NSAppearance* appearance = NSApp.effectiveAppearance;
    NSString* name = appearance.name;
    BOOL dark = [appearance bestMatchFromAppearancesWithNames:@[NSAppearanceNameAqua, NSAppearanceNameDarkAqua]] == NSAppearanceNameDarkAqua;
}

Borzh的回答也有所帮助,但似乎比其他答案更脆弱。