본문 바로가기
Swift

SwiftUI: 온보딩

by songmoro 2023. 8. 7.
728x90

Onboarding: 신입 사원이 조직 구성원이 되기 위해 필요한 지식, 기술, 행동을 교육하는 과정

 

앱에서 온보딩이라 하면 보통 최초로 실행했을 때 앱에 대한 정보 또는 사용 방법을 제공하기 위한 화면을 지칭합니다.

 

예를 들어,

게임이라면 처음 다루는 플레이어가 조작법에 익숙해질 수 있는 튜토리얼이 될 것이고,

헬스 케어라면 건강 앱에 대한 권한 허용과 정보 수집 및 이용에 대한 서명을 다룰 수 있겠죠?

 

SwiftUI에서 온보딩을 사용한다면 주로 AppStorage를 사용해요.

 

AppStorage: A property wrapper type that reflects a value from UserDefaults and invalidates a view on a change in value in that user default.

 

대충 UserDefaults라는 녀석의 값을 반영하는 프로퍼티 래퍼라는 것 같네요.

앱을 처음 시작하는 사람을 위한 온보딩을 만들어보겠습니다.

 

온보딩 여부를 확인하기 위해 Bool을 사용합니다.

struct ContentView: View {
    @State var isOnboarding: Bool = false
    
    var body: some View {
        if isOnboarding { // MARK: Main
            VStack {
                Image(systemName: "globe")
                    .imageScale(.large)
                    .foregroundColor(.accentColor)
                Text("Hello, world!")
            }
            .padding()
        } //: Main
        else { // MARK: Onboarding
            Button {
                isOnboarding = true
            } label: {
                Text("시작하기")
            }
        } //: Onboarding
    }
}

 

하지만 State는 앱이 새로 실행될 때 저장되지 않기 때문에 이를 AppStorage로 바꿔줄게요.

@AppStorage()를 입력한 상태로 ⌃ + ␣ 를 눌러주면 Key 값으로 String을 받는 걸 확인할 수 있어요.

 

isOnboarding이라는 Key 값을 받는 AppStorage 프로퍼티와 변수를 선언해 보겠습니다.

struct ContentView: View {
    @AppStorage("isOnboarding") var isOnboarding: Bool = false
    
    var body: some View {
        if isOnboarding { // MARK: Main
            VStack {
                Image(systemName: "globe")
                    .imageScale(.large)
                    .foregroundColor(.accentColor)
                Text("Hello, world!")
            }
            .padding()
        } //: Main
        else { // MARK: Onboarding
            Button {
                isOnboarding = true
            } label: {
                Text("시작하기")
            }
        } //: Onboarding
    }
}

 

조금 더 모듈화를 해볼게요.

온보딩 버튼을 따로 컴포넌트로 만들어준다. (⌘ + Left Click → Extract SubView)

 

struct ContentView: View {
    @AppStorage("isOnboarding") var isOnboarding: Bool = false
    
    var body: some View {
        if isOnboarding { // MARK: Main
            VStack {
                Image(systemName: "globe")
                    .imageScale(.large)
                    .foregroundColor(.accentColor)
                Text("Hello, world!")
            }
            .padding()
        } //: Main
        else { // MARK: Onboarding
            ExtractedView()
        } //: Onboarding
    }
}

struct ExtractedView: View {
    var body: some View {
        Button {
            isOnboarding = true
        } label: {
            Text("시작하기")
        }
    }
}

 

ExtractedView에도 isOnboarding을 추가하고, 따로 파일로 만들어줍시다.

struct ExtractedView: View {
    @AppStorage("isOnboarding") var isOnboarding: Bool = false
    
    var body: some View {
        Button {
            isOnboarding = true
        } label: {
            Text("시작하기")
        }
    }
}

 

마지막 작업

이건 선호도에 따라 갈릴 수 있다고 생각해요.

지금은 온보딩과 ContentView 밖에 없지만 프로젝트를 진행할 땐 ContentView에 다른 다양한 코드들이 추가되겠죠?

 

그래서 개인적으로 ContentView에 온보딩 분기가 있는 것보다 메인 앱에 있는 게 더 깔끔하다고 생각하는데 이에 대한 의견을 공유해 주세요!

struct OnboardingExampleApp: App {
    @AppStorage("isOnboarding") var isOnboarding: Bool = false
    
    var body: some Scene {
        WindowGroup {
            if isOnboarding { // MARK: ContentView
                ContentView()
            } //: ContentView
            else { // MARK: Onboarding
                ExtractedView()
            } //: Onboarding
        }
    }
}

 

그렇게 나온 결과물

물론, HIG에 따르면 이상적으로 온보딩 없이 사용자가 경험해 보고 익히길 권장하지만, 그래도 애플 생태계에서 흔하게 접할 수 없거나, 사용자가 낯선 환경이라고 느낀다면 혼란을 겪기 전에 온보딩 경험을 제공하는 것도 좋다고 생각합니다.

728x90

'Swift' 카테고리의 다른 글

Vision: visionOS simulator  (0) 2023.08.22
Vision: visionOS란?  (0) 2023.08.22
SwiftUI: map, compactMap, flatMap  (0) 2023.08.11
SwiftUI: Mask Design  (0) 2023.08.11
SwiftUI: BlendMode  (0) 2023.08.09