21

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

4

6 回答 6

26

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

询问currentAppearance通常也不是一个好主意,因为视图可能被明确设置为浅色模式,或者您想知道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方法来获取someView.effectiveAppearance.isDark(最好选择一个未来不太可能被 Apple 使用的名称,例如通过添加供应商前缀)。

于 2018-09-19T13:04:31.793 回答
19

我已经使用当前外观检查系统是否为 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);
}

有关更多信息暗模式文档

于 2018-08-03T12:02:26.407 回答
9

斯威夫特 4

func isDarkMode(view: NSView) -> Bool {
    if #available(OSX 10.14, *) {
        return view.effectiveAppearance.bestMatch(from: [.darkAqua, .aqua]) == .darkAqua
    }
    return false
}
于 2018-11-09T01:45:56.900 回答
3

一个视图实际上有 8 种可能的外观,其中 4 种是普通使用的。那是,

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

直接比较

appearance.name == NSAppearanceNameDarkAqua;

如果对比度增加,则可能无法检测暗模式。因此,请始终使用bestMatchFromAppearancesWithNames

考虑到高对比度的外观以获得更好的可访问性甚至更好。

于 2019-07-31T13:21:29.727 回答
2

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

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

所以,首先我必须按照 Saúl Moreno 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 的回答也有所帮助,但似乎比其他人更脆弱。

于 2019-06-29T12:41:47.290 回答
0

要知道应用外观是否为深色,请使用以下代码:

+ (BOOL)isDarkMode {
    NSString *interfaceStyle = [NSUserDefaults.standardUserDefaults valueForKey:@"AppleInterfaceStyle"];
    return [interfaceStyle isEqualToString:@"Dark"];
}
于 2019-06-15T20:01:14.860 回答