MojaveおよびXcode10を持ってないので動作確認できてません
ダークモードに対応するために作った。
ついでに「アクセシビリティ」環境設定の「コントラストを上げる」にも対応した。
システムが提供する名前付きのNSColorはシステムが勝手にやってくれるので何もやらなくてもよい。
まずは適切な名前付きNSColorを用いるようにすべきである。
これは10.13及びそれより前のmacOSもターゲットに入れた方法である。
10.14以上のみをターゲットとする場合は Asset Catalog の Colors を用いるべきである。
富豪プログラマなので独自に定義したカスタムカラーにいかに簡単にアクセスするかを最上位の目的とした。
この方法を用いると描画パフォーマンスが低下する恐れがある。
使い方
draw(_:)内などで使用する。
モードの変更の通知がよくわからない。
モードが変わると NSWindow#display() などが呼び出されるようだ。
func draw(_ dirtyRect: NSRect) {
// モードに準じた色が得られる
let borderColor = ColorSetManager.current[.borderColor]
borderColor.set()
...
}
登場する人
- protocol
- ColorSet 色が集まってる
- SpecialColorSet スペシャルな色が集まってる
- struct
- ColorSetManager 神様。全部知ってる。 名前を ColorSetGod にするか悩んだ。
- ColorName 色の名前が定義されてる。
- BaseColorSet 通常時の色のセット。
- そのたColorSet SpecialColorSet の具象化されたもの
- enum
- AppearanceMode あぴあらんす!
主要な人
ColorSet protocol
ColorNameからNSColorがもらえるsubscriptが宣言されてる。
protocol ColorSet {
subscript(named: ColorName) -> NSColor { get }
}
ColorSetManager struct
現在の使用するべき ColorSet を知っている。
struct ColorSetManager {
static var current: ColorSet { ... }
}
脇役の人
AppearanceMode enum
現在のモードを表す内部的なenum。
現在のモードも教えてくれる。
enum AppearanceMode {
case normal
case highContrast
case dark
case highContrastDark
}
extension AppearanceMode {
static var current: AppearanceMode { ... }
}
ColorName struct
色の名前。 initは privateの方がイイかも
static let で色を追加していく。
struct ColorName {
let name: String
init(_ name: String) {
self.name = name
}
}
extension ColorName {
static let asokoNoAnoBubun = ColorName("asokoNoAnoBubun")
}
裏方の人 (private)
BaseColorSet struct
inherit from ColorSet
基本となるカラーセット。
外部からは隠されている。
private struct BaseColorSet: ColorSet { ... }
SpecialColorSet protocol
inherit from ColorSet
特殊なモードでのカラーセット。
色の定義がない場合は BaseColorSet の色を返すように protocol extension が定義されている。
外部からは隠されている。
private protocol SpecialColorSet: ColorSet {
func color(named: ColorName) -> NSColor?
}
private extension SpecialColorSet {
subscript(named: ColorName) -> NSColor {
return color(named: named) ?? BaseColorSet.shared[named]
}
}
HighContrastColorSet struct
inherit from SpecialColorSet
DarkModeColorSet struct
inherit from SpecialColorSet
HighContrastDarkModeColorSet struct
inherit from SpecialColorSet
それぞれのモードでの具象型
外部からは隠されている。
現在のモードの識別
現在のモードの取得方法は10.14とそれ以前で変わっている。
前述通りMojaveおよびXcode10を持ってないので動くかどうかは不明。
extension AppearanceMode {
static var current -> AppearanceMode {
if #available(macOS 10.14, *) {
return currentMode1014()
}
/// macOS 10.13までは NSWorkspaceから。DarkModeはない。
if NSWorkspace.shared.accessibilityDisplayShouldIncreaseContrast {
return .highContrast
}
return .normal
}
@available(macOS 10.14, *)
private static func currentMode1014() -> AppearanceMode {
// 10.14ではNSAppearance.current.nameだけを調べればいい
switch NSAppearance.current.name {
case .aqua: return .normal
/// not available in macOS 10.13 SDK
// macOS 10.14 SDKがないのでコンパイル不能。コメントアウト
// case .accessibilityHighContrastAqua: return .highContrast
//
// case .darkAqua: return .dark
//
// case .accessibilityHighContrastDarkAqua: return .highContrastDark
default: return .normal
}
}
}