在macOS 10.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未来不太可能使用的名称,例如通过添加供应商前缀)。
如果系统是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
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
}
要知道应用程序外观是否为暗,请使用下一个代码:
+ (BOOL)isDarkMode {
NSString *interfaceStyle = [NSUserDefaults.standardUserDefaults valueForKey:@"AppleInterfaceStyle"];
return [interfaceStyle isEqualToString:@"Dark"];
}
对我来说,这些答案都不起作用,如果我想要一个全局状态,而不是每个视图,并且我无法访问该视图,我希望收到更新通知。
解决方案是在主线程中请求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的回答也有所帮助,但似乎比其他人更脆弱。