MacOS 10.14では、ユーザーはシステム全体の明るい外観または暗い外観を採用することを選択でき、現在のモードに応じていくつかの色を手動で調整する必要があります。
通常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将来、たとえばベンダープレフィックスを追加することにより)。
システムが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);
}
詳細情報 ダークモードドキュメント
スイフト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
}
ビューには実際には8つの appearances があり、そのうちの4つは通常の使用です。あれは、
NSAppearanceNameAqua
ライトモード、NSAppearanceNameDarkAqua
ダークモード、NSAppearanceNameAccessibilityHighContrastAqua
コントラストを高めたライトモード(アクセシビリティから設定)、NSAppearanceNameAccessibilityHighContrastDarkAqua
コントラストを高めたダークモード。直接比較
appearance.name == NSAppearanceNameDarkAqua;
コントラストが増加している場合、ダークモードの検出に失敗する可能性があります。したがって、代わりに常にbestMatchFromAppearancesWithNames
を使用してください。
また、アクセシビリティを向上させるために、コントラストの高い外観を考慮することをお勧めします。
appの外観が暗いかどうかを確認するには、次のコードを使用します。
+ (BOOL)isDarkMode {
NSString *interfaceStyle = [NSUserDefaults.standardUserDefaults valueForKey:@"AppleInterfaceStyle"];
return [interfaceStyle isEqualToString:@"Dark"];
}
ビューごとではなくグローバルな状態が必要で、ビューにアクセスできず、更新の通知を受け取りたい場合、私にとってこれらの答えはどちらも機能しませんでした。
解決策は、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からの回答は役に立ちましたが、他のものよりも壊れやすいようです。