在 macOS 10.14 中,用户可以选择采用系统范围的浅色或深色外观,我需要根据当前模式手动调整一些颜色。
6 回答
由于您通常通过的实际外观对象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 使用的名称,例如通过添加供应商前缀)。
我已经使用当前外观检查系统是否为 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);
}
有关更多信息暗模式文档
斯威夫特 4
func isDarkMode(view: NSView) -> Bool {
if #available(OSX 10.14, *) {
return view.effectiveAppearance.bestMatch(from: [.darkAqua, .aqua]) == .darkAqua
}
return false
}
一个视图实际上有 8 种可能的外观,其中 4 种是普通使用的。那是,
NSAppearanceNameAqua
灯光模式,NSAppearanceNameDarkAqua
黑暗模式,NSAppearanceNameAccessibilityHighContrastAqua
增加对比度的灯光模式(从辅助功能设置),NSAppearanceNameAccessibilityHighContrastDarkAqua
增加对比度的暗模式。
直接比较
appearance.name == NSAppearanceNameDarkAqua;
如果对比度增加,则可能无法检测暗模式。因此,请始终使用bestMatchFromAppearancesWithNames
。
考虑到高对比度的外观以获得更好的可访问性甚至更好。
对我来说,如果我想要一个全局状态,而不是每个视图,并且我无权访问视图,并且我希望收到更新通知,那么这些答案都不起作用。
解决方案是在主线程中请求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 的回答也有所帮助,但似乎比其他人更脆弱。
要知道应用外观是否为深色,请使用以下代码:
+ (BOOL)isDarkMode {
NSString *interfaceStyle = [NSUserDefaults.standardUserDefaults valueForKey:@"AppleInterfaceStyle"];
return [interfaceStyle isEqualToString:@"Dark"];
}