Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/macos/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c 如何在macOS 10.14上检测到暗模式?_Objective C_Macos_Appearance_Macos Mojave - Fatal编程技术网

Objective c 如何在macOS 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

在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;
要检测视图控制器中模式的变化,方法如下:

- (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不同