[macOS][Swift4.2] Mac 앱에서 Mojave의 외관 모드 전환에 대응

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.appearanceNSAppearance 로 설정하면 시스템의 설정 대신 지정한 외관 모드가 채용되므로 시스템에서의 외관 모드 변경에 좌우되지 않는다.
    양쪽 대응하면 개발·디자인 모두 비용이 들기 때문에 어느 쪽인가 밖에 대응하고 싶지 않은 경우는 이 방법을 사용해 고정치로서 두면 좋다.
    // 外観モードをライトのみサポートする
    NSApplication.shared.appearance = NSAppearance(named: .aqua)
    

    외관 모드가 변경되었을 때의 핸들링


    NSView.viewDidChangeEffectiveAppearance() 를 사용할 수 있다.
    오버라이드 해 두면 외관 모드가 변경되었을 때에 불리기 때문에 effectiveAppearance 에 따라서 묘화 내용을 변경해 재묘화하면 OK.

    HogeView.swift
    override func viewDidChangeEffectiveAppearance() {
        print(NSApplication.shared.effectiveAppearance.name)
    }
    

    macOS 10.13 이전



    외관 모드는 macOS 10.14 이후 밖에 사용할 수 없기 때문에 양쪽 대응하는 경우, if 분기해 두어 10.13 이전은 NSAppearance.Name.aqua 의 경우와 같은 처리에 흐르도록 해 두면 좋다.

    HogeView.swift
    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()
        }
    }
    


    Supporting Dark Mode in Your Interface

    좋은 웹페이지 즐겨찾기