본문 바로가기
Project/SwiftUI 블록와이드

[SwiftUI Project] 다크모드/라이트모드 전환 버튼 만들기

by iOS_woo 2022. 10. 27.

다크모드 전환 예시

이번에는 다크모드/라이트모드를 전환할 수 있는 버튼을 작업하였습니다.

 

UserDefault의 값을  @State처럼 반영하고 변경할 수 있게 해주는 @AppStorage 라는 것을 사용합니다.

@State는 앱이 종료되면 메모리에서 해제되는 반면, @AppStorage는 값이 저장된다는 차이가 있습니다. 

@AppStorage는 iOS14+부터 지원합니다!

 

 

1. Assets에서 다크모드에서 사용될 컬러셋을 지정해줍니다. (ex: 배경색, 폰트색, 버튼색 등등)

 

2. 부모뷰에서 isDarkMode 변수를 만들어주고, Bool 값에 따라서 ColorScheme이 변경될 수 있는 코드를 작성합니다.

import SwiftUI

@main
struct SwiftUICoinApp: App {

    생략
    @AppStorage("isDarkMode") private var isDarkMode = false <-- 다크모드를 사용하나요?
    
    var body: some Scene {
        WindowGroup {
            NavigationView {
                생략
            }
            생략
            .environment(\.colorScheme, isDarkMode ? .dark : .light) <-- 다크모드/라이트모드 전환
        }
    }
}

 

3. View에서 다크모드/라이트모드를 바꿔줄 수 있게 버튼을 만들어 주면 완성입니다.

import SwiftUI

struct SettingsView: View {
    
    @AppStorage("isDarkMode") private var isDarkMode = false // UserDefault
    @State private var isDark: Bool = false // 더보기 화면
    생략 
    
    var body: some View {
        VStack(spacing: 0) {
            settingHeader
            settingList
            Spacer()
        }
        
        생략
        // 더보기 화면이 보여지면 UserDefault의 값에 따라서 isDark의 상태를 변환시켜줍니다.
        .onAppear {
            if isDarkMode {
                isDark = true
            } else {
                isDark = false
            }
        }
    }
}

private extension SettingsView {
    var settingHeader: some View {
        HStack {
            IconView(iconName: "chevron.left")
                .onTapGesture {
                    presentationMode.wrappedValue.dismiss()
                    
                    // 뒤로가기 버튼을 누르면 isDark 변수의 상태에 따라서 UserDefault에 적용해줍니다.
                    if isDark {
                        isDarkMode = true
                    } else {
                        isDarkMode = false
                    }
                }
            Spacer()
            Text("더보기")
                .font(.headline)
            Spacer()
            
            // 더보기 화면에만 적용되는 isDark 변수를 전환해줍니다.
            Button {
                isDark.toggle()
            } label: {
                IconView(iconName: isDark ? "moon.fill" : "sun.min.fill")
            }
        }
    }
   생략
}

@AppStorage 변수가 아닌 @State 변수도 포함해주었는데요. 

처음에  @AppStorage만 변경을 해주었을 때 Navigation Link가 자동으로 dismiss되는 버그(?)가 발생하였습니다. 

제 생각에는 UserDefault가 변경되면서 화면을 새롭게 그리게 되면서 발생하는 현상이 아닐까 싶은데.. 

 

검색해도 마땅히 해결책이 안 나와서 임시방편으로 @State 변수를 만들어서 더보기 화면의 색을 변경해주었습니다. 

그 후 유저가 동작을 마치고 홈화면으로 돌아가기 위해 "뒤로가기"버튼을 누르면 UserDefault 값에 저장되도록 해주었어요.

 

원하던 기능은 달성할 수 있었는데 "뒤로가기" 버튼을 눌렀을 때 isDarkMode의 값이 뒤늦게 변경되니 dismiss  될 때 화면이 번쩍하는 부작용이 있습니다. 

추후 다크모드를 변경할 때 쓰이는 코드들을 많이 보면서 해결해야 할 것 같아요. 

 

@AppStorage 참고 블로그: 

 

@AppStorage와 UserDefaults

안녕하세요. iOS 개발자 에이든입니다!👦🏻 App에 간단하게 값들을 저장하고 싶을 때 사용하는 방법!!🤔 바로바로 UserDefaults!!! 이번 시간에는 UserDefaults와 iOS 14부터 새로 생긴 SwitUI의 AppStorage에.

aiden-ios.tistory.com

 

다크모드/라이트모드 참고 유튜브: 

 

댓글