Objective c 如何在macOS 10.14上检测到暗模式?
在macOS 10.14中,用户可以选择采用系统范围内的亮或暗外观,我需要根据当前模式手动调整一些颜色。如果系统为10.14,我使用了当前外观检查Objective c 如何在macOS 10.14上检测到暗模式?,objective-c,macos,appearance,macos-mojave,Objective C,Macos,Appearance,Macos Mojave,在macOS 10.14中,用户可以选择采用系统范围内的亮或暗外观,我需要根据当前模式手动调整一些颜色。如果系统为10.14,我使用了当前外观检查 + (BOOL)isDarkMode { NSAppearance *appearance = NSAppearance.currentAppearance; if (@available(*, macOS 10.14)) { return appearance.name == NSAppearanceNameDark
+ (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;
要检测视图控制器中模式的变化,方法如下:
- (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);
}
有关详细信息由于通常通过
有效外观
获得的实际外观对象是复合外观,因此直接询问其名称可能不是可靠的解决方案
询问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
(最好选择一个苹果将来不太可能使用的名称,例如添加供应商前缀)。
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úl Moreno Abril的指示注册,代码如下
[NSDistributedNotificationCenter.defaultCenter添加观察者:自选择器:@selector(themeChanged:)名称:@“AppleInterfaceHemeChangedNotification”对象:nil];
然后在回调方法上编写如下内容
-(作废)更改后的:(NSNotification*)通知{
[self-performSelectorOnMainThread:@selector(themeChangedOnMainThread),对象为nil waitUntilDone:false];
}
然后是实际代码:
-(无效)机械更改主线程{
NSAppearance*appearance=NSApp.effectiveAppearance;
NSString*name=appearance.name;
BOOL dark=[外观最佳匹配来自外观名称:@[NSAppearanceNameAqua,NSAppearanceNameDarkAqua]==NSAppearanceNameDarkAqua;
}
Borzh的答案也有帮助,但它似乎比其他答案更脆弱。实际上有8种视图可能,其中4种用于普通用途。就是
NSAppearanceNameAqua
灯光模式NSAppearanceNameDarkAqua
黑暗模式NSAppearanceNameAccessibilityHighContrastAqua
对比度增强的灯光模式(从可访问性设置)NSAppearanceNameAccessibilityHighContrastDarkAqua
对比度增强的暗模式李>
直接比较
appearance.name==NSAppearanceNameDarkAqua代码>
如果对比度增加,则可能无法检测到暗模式。因此,请始终使用bestmatchfromAppearancesswithnames
考虑到高对比度外观更好的可访问性更好 对外观更改作出反应的最佳方法是-[NSView viewdidchangeffectiveappearance]
。您还可以KVO视图的effectiveAppearance
属性,例如,如果要对视图控制器中的外观更改做出反应。请记住,视图的外观可能不同于“当前”或系统外观。NSAppearance.currentAppearance
在用户在亮模式和暗模式之间切换时不总是工作,反之亦然。NSAppearance.currentAppearance
返回对象在当前线程上处于活动状态的外观,因此您无法确定,因为当前对象可能具有Aqua
或深绿色
指定在继承的
位置。因此,如果使用someView.effectiveAppearance
appleInterfaceTheMechanedNotification
对我来说不起作用,那么最好的解决方案就是使用someView.effectiveAppearance
。相反,可以使用viewDidLayout
调用暗/亮模式方法。您可以使用NSApp.mainWindow.effectiveAppearance
@MuntashirAkon:您不需要从视图中调用它,这是不相关的。你只需要一个确定上下文的视图,比如作为后备的应用程序主视图。你必须从drawRect
调用它吗?那么viewDidLayout
呢?这个代码以前对我有用。但在将Xcode更新到11.4之后,它神秘地不再工作了。在亮模式和暗模式下,它都返回Aqua模式。还有其他人也有同样的问题吗?@93sauu似乎有比赛条件在这样做。NSApp.effectiveAppearance似乎是检测系统范围设置的更好方法。我建议取消该选项:在许多情况下NSAppearance.currentAppearance
可能会给出错误的结果(例如,如果在方法之外调用它,并且用户更改了系统外观,NSAppearance.currentAppearance
仍可能返回旧的系统外观)。因此,请始终询问其有效外观的具体视图。此外,检查外观.name==.darkAqua
在某些情况下也可能是错误的,因为实际外观是“复合物”。这就是存在的原因,应该改为使用。感谢您的建议。答案已更新。NSUserDefaults。standardUserDefaults
可能与t不同