web-dev-qa-db-ja.com

macOS 10.14でダークモードを検出するにはどうすればよいですか?

MacOS 10.14では、ユーザーはシステム全体の明るい外観または暗い外観を採用することを選択でき、現在のモードに応じていくつかの色を手動で調整する必要があります。

10

通常effectiveAppearanceを介して取得する実際の外観オブジェクトは複合外観であるため、名前を直接尋ねることはおそらく信頼できるソリューションではありません。

ビューを明示的にライトモードに設定したり、ビューが_drawRect:_の外側で明るいか暗いかを知りたい場合、通常、currentAppearanceを要求することは良い考えではありません。モードを切り替えた後、誤った結果が表示される場合があります。

私が思いついた解決策は次のようになります。

_BOOL appearanceIsDark(NSAppearance * appearance)
{
    if (@available(macOS 10.14, *)) {
        NSAppearanceName basicAppearance = [appearance bestMatchFromAppearancesWithNames:@[
            NSAppearanceNameAqua,
            NSAppearanceNameDarkAqua
        ]];
        return [basicAppearance isEqualToString:NSAppearanceNameDarkAqua];
    } else {
        return NO;
    }
}
_

_someView.appearance_を明示的に設定すると、特定のビューの外観が別のビューの外観と異なる場合があるため、appearanceIsDark(someView.effectiveAppearance)のように使用します。

NSAppearanceにカテゴリを作成し、- (BOOL)isDarkメソッドを追加して_someView.effectiveAppearance.isDark_を取得することもできます(Apple将来、たとえばベンダープレフィックスを追加することにより)。

18
DarkDust

システムが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;

また、View Controllerでモードの変更を検出する方法は次のとおりです。

- (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);
}

詳細情報 ダークモードドキュメント

15

スイフト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
}
4
Joey

ビューには実際には8つの appearances があり、そのうちの4つは通常の使用です。あれは、

  1. NSAppearanceNameAquaライトモード、
  2. NSAppearanceNameDarkAquaダークモード、
  3. NSAppearanceNameAccessibilityHighContrastAquaコントラストを高めたライトモード(アクセシビリティから設定)、
  4. NSAppearanceNameAccessibilityHighContrastDarkAquaコントラストを高めたダークモード。

直接比較

appearance.name == NSAppearanceNameDarkAqua;

コントラストが増加している場合、ダークモードの検出に失敗する可能性があります。したがって、代わりに常にbestMatchFromAppearancesWithNamesを使用してください。

また、アクセシビリティを向上させるために、コントラストの高い外観を考慮することをお勧めします。

0
L.-T. Chen

appの外観が暗いかどうかを確認するには、次のコードを使用します。

+ (BOOL)isDarkMode {
    NSString *interfaceStyle = [NSUserDefaults.standardUserDefaults valueForKey:@"AppleInterfaceStyle"];
    return [interfaceStyle isEqualToString:@"Dark"];
}
0
Borzh

ビューごとではなくグローバルな状態が必要で、ビューにアクセスできず、更新の通知を受け取りたい場合、私にとってこれらの答えはどちらも機能しませんでした。

解決策は、NSApp.effectiveAppearanceはメインスレッドで、または少なくともafter現在のコールバックメソッドがシステムに戻りました。

そのため、最初に登録する必要があります。SaúlMoreno 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からの回答は役に立ちましたが、他のものよりも壊れやすいようです。

0
Panayotis