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

问题描述 投票:9回答:4

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

objective-c macos appearance macos-mojave
4个回答
14
投票

由于您通常通过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未来不太可能使用的名称,例如通过添加供应商前缀)。


14
投票

如果系统是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的更多信息


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
}

0
投票

要知道应用程序外观是否为暗,请使用下一个代码:

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

0
投票

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

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

所以,首先我必须按照SaúlMorenoAbril的指示注册,代码如下

[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的回答也有所帮助,但似乎比其他人更脆弱。

© www.soinside.com 2019 - 2024. All rights reserved.