macOS 10.14 Mojaveでは外観モード(=システム全体のUIの見栄え)を従来通りの明るい ライト 、新しく追加された暗めの ダーク に切り替えることができるようになった。
ダークモードによって、眼精疲労がかなり軽減されたので非常に重宝している。
WebViewの内容も切り替わったら嬉しいのに。
この外観モードを切り替えた時、Macアプリでどのように対応したら良いのか記載したい。
標準のUIコンポーネントのみで構成されたアプリであれば、Xcode10以降でビルドすれば特に対応の必要がなく自動的に再描画してくれる。(*)
しかし、自前のビューを配置していたり直接描画していたりする場合、標準コントロールだけが別のモードになって、自前ビューの部分が切り替わらず描画バグっぽく見えてしまうことがあるので対応の必要が出てくる。
* Xcode9以前でビルドされたバイナリでは従来通り強制的にライトのみのサポートになる模様。
- Xcode10.1
- Swift4.2
- macOS Mojave 10.14.2
外観モードを変更するには?
システム環境設定 > 一般に「外観モード」があり、ライトかダークが選択できるようになっている。
外観モードの取得
システムで設定されている外観モードは以下で取得することができる。
let appearance = NSApplication.shared.effectiveAppearance
判定は NSAppearance.name
でできそうだ。
ライトなら .aqua
、ダークなら .darkAqua
となっている。(まだアクアだったのか。。)
switch NSApplication.shared.effectiveAppearance.name {
case .aqua:
print("外観モードはライト")
case .darkAqua:
print("外観モードはダーク")
default:
assertionFailure()
}
外観モードの指定
NSApplication.shared.appearance
に NSAppearance
をセットすることでシステムでの設定に代わり、指定した外観モードが採用されるためシステムでの外観モード変更に左右されない。
両方対応すると開発・デザインともにコストがかかるのでどちらかしか対応したくない場合はこの方法を使って固定値としておけば良い。
// 外観モードをライトのみサポートする
NSApplication.shared.appearance = NSAppearance(named: .aqua)
外観モードが変更された時のハンドリング
NSView.viewDidChangeEffectiveAppearance()
が使える。
オーバーライドしておけば外観モードが変更された時に呼ばれるので effectiveAppearance
に応じて描画内容を変更して再描画すればOK。
override func viewDidChangeEffectiveAppearance() {
print(NSApplication.shared.effectiveAppearance.name)
}
macOS 10.13以前
外観モードはmacOS 10.14以降しか使えないので両方対応する場合、if分岐しておき10.13以前は NSAppearance.Name.aqua
の場合と同様の処理に流れるようにしておくと良い。
func setupAppearance() {
func setupForLight() {
textColor = .black
backgroundColor = .white
}
func setupForDark() {
textColor = .white
backgroundColor = .black
}
if #available(macOS 10.14, *) {
switch NSApplication.shared.effectiveAppearance.name {
case .aqua:
setupForLight()
case .darkAqua:
setupForDark()
default:
assertionFailure()
}
} else {
setupForLight()
}
}