Danny의 iOS 컨닝페이퍼
article thumbnail

[TIL #31] 2023 / 06 / 23

iOS13부터 다크모드가 도입되었습니다.

 

라이트 및 다크모드 적용하는 방법들을 알아봅시다.

 

 

Info.plist로 적용 방법

기본적인 사용 방법으로는 Info.plist에서 Appearance를 통해 스타일을 정해주는 겁니다.

Value값을 통해 원하는 스타일을 선택할 수 있습니다. (Light, Dark)

 

 

앱 내에서 Appearance 적용 방법

Info.plist 대신, SceneDelegate 및 UIViewController에서도 코드를 통해 Appearance을 변경해 줄 수 있습니다.

바로, overrideUserInterfaceStyle를 이용하여 다크 및 라이트 모드 변경이 가능합니다.

 

 

window에서 전역 설정

화면이 생성되는 시점인 SceneDelegate에서 설정을 해주면, 모든 뷰컨트롤러에서 적용이 됩니다.

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    
    guard let windowScene = (scene as? UIWindowScene) else { return }
    let window = UIWindow(windowScene: windowScene)
    
    // 라이트 모드 (다크모드: dark)
    window.overrideUserInterfaceStyle = .light
    
    ... 생략 ...
}

 

 

ViewController에서 Appearance 설정

각각의 ViewController마다 원하는 Appearance을 설정해 줄 수 있습니다.

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 라이트 모드 (다크모드: dark)
        self.overrideUserInterfaceStyle = .light
    }
}

 

그리고 또, 단일 View에서도 사용이 가능합니다.

let view = UIView()
view.overrideUserInterfaceStyle = .light

 

 

시멘틱 컬러(Semantic colors)

라이트 및 다크모드를 동시에 구현할 때, 시멘틱 컬러(Semantic colors)를 이용해서 만들어 준다면,

다크모드 대응이 많이 수월해집니다.

 

Swift에서 시멘틱 컬러는 다크모드와 라이트 모드를 전환할 때, 자동으로 화면에 적절한 색상을 표현해 준다고 하네요.

보통 system이 들어간 색들 모두 Semantic colors가 적용이 돼있는 것 같네요.

 

이 분 이 적용되는 색상들을 보기편하게 앱으로 만들어놨던데, 시간 되면 한번 참고해 보세요.

(소근소근) 저도 이 앱의 컨트리뷰터라는...

간단히 어떤 차이가 있는지 사진을 통해 참고해 보세요.

 

 

스위치를 이용하여 Appearance 변경

간단히 UISwitch로 다크모드를 On/Off 하는 기능을 만들어 봅시다.

 

다크모드설정 같은 경우, 설정이 계속 유지돼야 하므로 UserDefaults를 사용하여 값을 유지해 주려합니다.

 

일단 스위치 설정부터 보면,

스위치가 켜지면 true값을 저장, 꺼지면 false로 UserDefaults에 저장해 줍니다.

@objc func darkModeSwitchToggled(_ sender: UISwitch) {
    if sender.isOn {
        UserDefaults.standard.set(true, forKey: "DarkModeEnabled")
    } else {
        UserDefaults.standard.set(false, forKey: "DarkModeEnabled")
    }
    // 여기에서 다크모드 설정은 UserDefaults 값에 따라서 변경됩니다.
    self.viewWillAppear(true)
}

 

이제 UserDefaults 값에 따라서, 다크모드 설정하는 코드를 만들어 봅시다.

다크모드 사용 방법은 위와 같고, windowScene에 접근해서 모든 뷰컨트롤러에서 즉시 반영되게 만들어봤습니다.

 

여기서 가장 중요한 부분은 상태바를 무조건 업데이트시켜줘야 합니다.

(상태바를 업데이트시켜주지 않으면, 상태창과 배경색이 같아서 보이지가 않아요!)

func checkDarkMode() {
    let isDarkModeEnabled = UserDefaults.standard.bool(forKey: "DarkModeEnabled")
    // 설정한 스위치를 유지시키기 위해 설정
    darkModeSwitch.isOn = isDarkModeEnabled
    
    // Scene으로 접근
    guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
          let window = windowScene.windows.first else { return }
    
    if isDarkModeEnabled {
        window.overrideUserInterfaceStyle = .dark
    } else {
        window.overrideUserInterfaceStyle = .light
    }
    // ⭐️ 필수 ⭐️ 상태바(시계, 배터리, 다이나믹 아일랜드 등)을 업데이트 시켜준다.
    self.setNeedsStatusBarAppearanceUpdate()
}

 

다음으로 뷰컨이 나타날 때마다, 다크모드를 체크하여 설정한 값이 유지되도록 만들어 줬습니다.

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    checkDarkMode()
}

 

그리고 현재 뷰컨이 처음 실행하는 뷰컨이 아닐 수도 있으므로,

SceneDelegate에서도 따로 UserDefaults를 갖고 다크모드 설정해 주면 될 것 같습니다.

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    
    guard let windowScene = (scene as? UIWindowScene) else { return }
    let window = UIWindow(windowScene: windowScene)
    
    let isDarkModeEnabled = UserDefaults.standard.bool(forKey: "DarkModeEnabled")
    
    if isDarkModeEnabled {
        window.overrideUserInterfaceStyle = .dark
    } else {
        window.overrideUserInterfaceStyle = .light
    }
    
    ... 생략 ...
}

 

아, 코드 중복이 거슬리는데... 깔끔한 다른 방식이 있을까요?

흠, 싱글톤으로 만들어야 했나... 일단, 참고만 하시고 고쳐서 사용하세요. ㅎ

 

 

참고

https://github.com/DanielY1108/SemanticUI

https://www.avanderlee.com/swift/dark-mode-support-ios/

https://velog.io/@minji0801/iOS-Swift

 

 

 

반응형
profile

Danny의 iOS 컨닝페이퍼

@Danny's iOS

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!