Overview

올해 WWDC19 이벤트에 흥미진진한 발표 중의 하나가 iOS 13을 사용하는 기기에서 다크 모드를 사용할 수 있다는 내용이었습니다. 시스템 전체적으로 다크 모드를 사용할 수 있으며, 앱에서 해당 모드를 지원하게 되면 앱에서 어두운 테마의 모습으로 나타납니다.

dark
[그림1] iOS 13에서의 일반 모드와 다크 모드의 설정 앱 화면


iOS 13에서 다크 모드 적용하기는 매우 쉽습니다. 하지만, 디자인적인 리소스가 필요하기 때문에 개발팀과 디자인팀의 협업이 필요합니다. 브랜디에서는 완벽하게 적용하기 위해 준비 중이며, 오늘은 어떤식으로 다크모드를 적용하는지 맛보는 시간을 가지도록 하겠습니다.


다크 모드에 색상 맞추기

다크 모드의 큰 특징 중 하나는 바로 색상입니다. 다크 모드 사용하기 전에는 색상들을 하드 코딩하여 특정 색상을 나타내도록 설정했습니다. 따라서 다크 모드일 때는 색상 값들을 다시 지정해야 합니다. 다수의 색상을 사용할 경우, 다크 모드일 때의 색상들을 다시 지정해야 하기 때문에 관리해야 하는 색상 값들이 많아지고 불편해질 수 있습니다. 이런 점을 해결하기 위해 애플에서는 Semantic colors라는 것을 제공합니다.


Semantic Colors

Semantic colors는 직역하면 “의미적 색채”의 뜻을 가지고 있는데, 조금 더 쉽게 이해하자면 ‘의미를 가진 색’으로 보면 됩니다. 예를 들어, ‘label’이라는 색상일 경우 텍스트 같은 문구에 사용하는 색상을 뜻합니다. 또한, ‘systemBackground’ 라는 색상은 배경색을 뜻하는 것으로 보면 됩니다. Semantic colors를 사용하면 좋은 점은, 개발자가 색상만 지정하면 나머지는 UIKit에서 작업합니다. 다크 모드인지 확인할 필요가 없고 시스템에서 알아서 적용합니다.

dark
[그림2] WWDC19 다크모드 발표 영상 중 일부


코드에서 적용하는 방법은 간단합니다. UIColor에서 기본적으로 제공하기 때문에 UIColor.black, UIColor.systemBackground 와 같이 사용하면 됩니다.

단, 관련한 semantic colors 들은 iOS 13 이상에서만 사용 가능합니다.

if #available(iOS 13, *) {
    view.backgroundColor = .systemBackground
    label.textColor = .label
} else {
    view.backgroundColor = .white
    label.textColor = .black
}


커스텀 색상 만들기

애플에서 제공하는 시스템 컬러는 사용하기 좋지만, 앱의 특성에 따라서 적용해야 하는 색상이 다를 수 있습니다. 커스텀 색상을 만들기 위해서는 다크 모드인지 아닌지 판별해야 하는데,
UITraitCollection.userInterfaceStyle 이라는 속성을 가지고 판별할 수 있습니다.
UITraitCollection.userInterfaceStyle == .dark 조건이 다크 모드이기 때문에 적용하고 싶은 색상을 나타나게 하면 됩니다.

let COLOR_BRANDI_PRIMARY: UIColor = {
    if #available(iOS 13, *) {
        return UIColor { (UITraitCollection: UITraitCollection) -> UIColor in
            if UITraitCollection.userInterfaceStyle == .dark {
                // Return color for Dark Mode
                return UIColor.rgb(red: 255, green: 100, blue: 92)
            } else {
                // Return color for Light Mode
                return UIColor.rgb(red: 255, green: 76, blue: 66)
            }
        }
    } else {
        // Return fallback color for iOS 12 and lower
        return UIColor.rgb(red: 255, green: 76, blue: 66)
    }
}()


다크 모드일 때의 이미지 적용 방법

이미지도 다크 모드일 때 적용하고 싶은 모습을 설정할 수 있습니다. 가장 쉬운 방법은 Image Asset Catalog를 이용합니다. Appearance를 Any, Dark로 변경하면 다크 모드일 때의 이미지를 추가할 수 있습니다. 똑같이 시스템에서 다크 모드일 때 해당 이미지를 사용하기 때문에, 개발자의 추가적인 작업은 필요 없습니다.

dark
[그림3] 다크 모드에서 적용하고 싶은 이미지 추가 화면


이미지 혹은 아이콘에 틴트 컬러 입히기

또 다른 방법은 틴트 컬러(tint color)를 입히는 방법입니다. 다양한 색상을 가지는 이미지의 경우 다크 모드일 때의 이미지가 필요하지만, 아이콘 혹은 네비게이션 바에 적용하는 이미지 같은 경우는 단순한 색상으로 이루어지는 경우가 많습니다. 해당 이미지들은 다크 모드일 때의 이미지를 추가하는 것보다 틴트 컬러를 변경하여 작업하는 것이 편리할 수 있습니다.

먼저 해당 이미지의 asset render를 template로 변경 후, 코드에서 아래와 같이 적용하면 됩니다.

dark
[그림4] 이미지 render를 template로 설정


let imageView = UIImageView()
imageView.image = UIImage(named: icTodayshippingListM)?.withRenderingMode(.alwaysTemplate)
imageView.tintColor = ResourceDataStore.colors().COLOR_BRANDI_TINT


다크 모드 테스트하는 방법

다크 모드를 적용하면 시뮬레이터 혹은 디바이스를 통해서 테스트 가능합니다. 시뮬레이터와 디바이스를 통해서 테스트하는 방법을 설명하겠습니다. 단, 이 또한 iOS 13 이상에서만 테스트 가능합니다.


시뮬레이터에서 다크 모드 전환하기

시뮬레이터에서 설정 앱 -> 개발자 -> Appearance에 있는 Dark Appearance 부분을 스위치 하면 됩니다.

dark
[그림5] 시뮬레이터 설정 화면


디버그 메뉴에서 다크 모드 전환하기

시뮬레이터로 디버그 중일 때, Environment Overrides window 이용하여 다크 모드로 전환할 수 있습니다.

dark
[그림6] Environment Overrides window를 이용하여 Interface Style을 바꿀 수 있음


스토리보드에서 다크 모드 전환하기

스토리보드 하단에 있는 여러 디바이스 옆에 Interface Style 부분에서 다크 모드 선택할 수 있습니다.

dark
[그림7] 스토리보드 하단 메뉴


디바이스에서 다크 모드 전환하기

디바이스에 있는 설정 앱 > 디스플레이 및 밝기 메뉴에 다크 모드로 화면 스타일을 지정할 수 있습니다. 하지만 조금 더 쉽게 하는 방법이 제어 센터 항목에 다크 모드 추가하여 사용하는 것입니다.

dark
[그림8] 제어 센터를 통한 다크 모드 전환


다크 모드 지원 안 하기

iOS 13에서는 기본적으로 다크 모드도 지원하도록 기본값이 설정되어 있어, 만약 다크 모드에서 제대로 대응하지 않으면 다크 모드일 때 하얀 화면 혹은 맞지 않는 UI가 나타날 수 있습니다. 아직 다크 모드 적용하기가 힘들다면 다크 모드를 지원하지 않도록 설정을 추가하면 됩니다.
간단하게 Info.plist 에서 UIUserInterfaceStyle 키에 Light 속성값을 추가하면 됩니다.


View Controller에서 다크 모드 지원 안 하기

아래 코드처럼 ViewController 별로 다크모드 지원 안하기를 설정하면 됩니다. 반대로 다크 모드만 지원하고 싶으면 .light 값으로 설정하면 됩니다.

override func viewDidLoad() {
    super.viewDidLoad()
    if #available(iOS 13.0, *) {
        overrideUserInterfaceStyle = .dark
    } else {
        // Fallback on earlier versions
    }
}


View에서 다크 모드 지원 안 하기

UIView에서도 동일하게 사용할 수 있습니다.

let view = UIView()
if #available(iOS 13.0, *) {
    view.overrideUserInterfaceStyle = .dark
} else {
    // Fallback on earlier versions
}


Window에서 다크 모드 지원 안 하기

Window도 마찬가지로 동일하게 사용할 수 있습니다.

if let window = UIApplication.shared.windows.first {
    if #available(iOS 13.0, *) {
        window.overrideUserInterfaceStyle = .light
    } else {
        // Fallback on earlier versions
    }
}


마치며

dark
[그림9] 브랜디의 라이트 모드와 다크 모드(예정) 모습


iOS 13에서 다크 모드를 지원하는 것은 간단합니다. 색상과 이미지만 잘 설정하면, 나머지는 UIKit에서 자동으로 처리하기 때문에 개발자가 하는 일이 적습니다. 기존에 이미지를 많이 사용했을 경우 디자인 팀과 협업하여 다크 모드일 때의 이미지와 색상을 정리하면, 멋진 다크 모드의 UI가 나타납니다. 브랜디는 조금 더 시간을 들여 완벽한 다크 모드를 지원하도록 하겠습니다. 기대해주세요!


참고

Implementing Dark Mode on iOS - WWDC 2019 - Videos - Apple Developer
https://stackoverflow.com/questions/56537855/is-it-possible-to-opt-out-of-dark-mode-on-ios-13


김주희 | MA팀
kimjh3@brandi.co.kr
브랜디, 오직 예쁜 옷만