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

Saú*_*ril 11 macos appearance objective-c macos-mojave

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

Dar*_*ust 19

由于您经常通过的实际外观对象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;
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以使用它,appearanceIsDark(someView.effectiveAppearance)因为如果您明确设置,特定视图的外观可能与另一个视图的外观不同someView.appearance.

您还可以创建一个类别NSAppearance并添加一个- (BOOL)isDark方法来获取someView.effectiveAppearance.isDark(更好地选择Apple将来不太可能使用的名称,例如通过添加供应商前缀).

  • 你可以使用`NSApp.mainWindow.effectiveAppearance` (4认同)

Saú*_*ril 16

如果系统是10.14,我已经使用了当前的外观检查

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

    return NO;
}
Run Code Online (Sandbox Code Playgroud)

并且在视图中检测模式的变化方法是:

- (void)updateLayer;
- (void)drawRect:(NSRect)dirtyRect;
- (void)layout;
- (void)updateConstraints;
Run Code Online (Sandbox Code Playgroud)

并且为了在视图控制器中检测模式的改变,方法是:

- (void)updateViewConstraints;
- (void)viewWillLayout;
- (void)viewDidLayout;
Run Code Online (Sandbox Code Playgroud)

使用通知:

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

-(void)themeChanged:(NSNotification *) notification {
    NSLog (@"%@", notification);
}
Run Code Online (Sandbox Code Playgroud)

有关暗模式文档的更多信息

  • 对外观更改做出反应的最佳方法是` - [NSView viewDidChangeEffectiveAppearance]`.您还可以KVO视图的`effectiveAppearance`属性,例如,如果您想对视图控制器中的外观更改做出反应.请记住,视图的外观可能与"当前"或系统外观不同. (2认同)
  • `NSAppearance.currentAppearance` 返回当前线程上处于活动状态的对象的外观,因此您无法确定,因为当前对象可能分配了 `Aqua` 或 `Dark Aqua` 代替了 `Inherited`。所以最好的解决方案是使用`someView.effectiveAppearance`。 (2认同)

Joe*_*oey 5

斯威夫特4

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

更新:

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

  • 同样,在某些情况下,对“ appearance.name == .darkAqua”的检查也可能是错误的,因为_actual_外观是“化合物”。这就是为什么[`bestMatch(from:)`](https://developer.apple.com/documentation/appkit/nsappearance/2980972-bestmatch)存在并应使用的原因。 (2认同)