如何在 macOS 10.14 上检测到暗模式?
How can dark mode be detected on macOS 10.14?
在 macOS 10.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);
}
由于您通常通过 effectiveAppearance
获得的实际外观对象是复合外观,因此直接询问其名称可能不是一个可靠的解决方案。
询问 currentAppearance
通常也不是一个好主意,因为视图可能被明确设置为浅色模式,或者您想知道视图在 [= 之外是浅色还是深色13=] 模式切换后可能会得到错误结果的地方。
我想出的解决方案是这样的:
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使用的名称,例如,通过添加供应商前缀)。
Swift 4
func isDarkMode(view: NSView) -> Bool {
if #available(OSX 10.14, *) {
return view.effectiveAppearance.bestMatch(from: [.darkAqua, .aqua]) == .darkAqua
}
return false
}
要知道 app 外观是否为深色,请使用下一个代码:
+ (BOOL)isDarkMode {
NSString *interfaceStyle = [NSUserDefaults.standardUserDefaults valueForKey:@"AppleInterfaceStyle"];
return [interfaceStyle isEqualToString:@"Dark"];
}
对我来说,如果我想要一个全局状态而不是每个视图,并且我无权访问该视图,并且我希望收到更新通知,那么这些答案都不起作用。
解决方案是在主线程中请求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 的回答也有帮助,但似乎比其他答案更脆弱。
一个视图实际上有8种可能appearances,其中4种是普通使用的。也就是说,
NSAppearanceNameAqua
灯光模式,
NSAppearanceNameDarkAqua
深色模式,
NSAppearanceNameAccessibilityHighContrastAqua
增强对比度的灯光模式(从辅助功能设置),
NSAppearanceNameAccessibilityHighContrastDarkAqua
增加对比度的深色模式。
直接比较
appearance.name == NSAppearanceNameDarkAqua;
如果对比度增加,可能无法检测到暗模式。因此,请始终使用 bestMatchFromAppearancesWithNames
。
最好考虑高对比度外观以获得更好的可访问性。
在 macOS 10.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);
}
由于您通常通过 effectiveAppearance
获得的实际外观对象是复合外观,因此直接询问其名称可能不是一个可靠的解决方案。
询问 currentAppearance
通常也不是一个好主意,因为视图可能被明确设置为浅色模式,或者您想知道视图在 [= 之外是浅色还是深色13=] 模式切换后可能会得到错误结果的地方。
我想出的解决方案是这样的:
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使用的名称,例如,通过添加供应商前缀)。
Swift 4
func isDarkMode(view: NSView) -> Bool {
if #available(OSX 10.14, *) {
return view.effectiveAppearance.bestMatch(from: [.darkAqua, .aqua]) == .darkAqua
}
return false
}
要知道 app 外观是否为深色,请使用下一个代码:
+ (BOOL)isDarkMode {
NSString *interfaceStyle = [NSUserDefaults.standardUserDefaults valueForKey:@"AppleInterfaceStyle"];
return [interfaceStyle isEqualToString:@"Dark"];
}
对我来说,如果我想要一个全局状态而不是每个视图,并且我无权访问该视图,并且我希望收到更新通知,那么这些答案都不起作用。
解决方案是在主线程中请求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 的回答也有帮助,但似乎比其他答案更脆弱。
一个视图实际上有8种可能appearances,其中4种是普通使用的。也就是说,
NSAppearanceNameAqua
灯光模式,NSAppearanceNameDarkAqua
深色模式,NSAppearanceNameAccessibilityHighContrastAqua
增强对比度的灯光模式(从辅助功能设置),NSAppearanceNameAccessibilityHighContrastDarkAqua
增加对比度的深色模式。
直接比较
appearance.name == NSAppearanceNameDarkAqua;
如果对比度增加,可能无法检测到暗模式。因此,请始终使用 bestMatchFromAppearancesWithNames
。
最好考虑高对比度外观以获得更好的可访问性。