
Modal, Navigation, Tab을 응용하여 나만의 화면을 만드는 실습을 진행해봤다.
온보드 모달로 사용할 화면을 SwiftUI 파일로 생성한다. ZStack으로 배경 색상을 지정하고, 그 안에 VStack으로 이미지 및 텍스트를 설정한다.
import SwiftUI
struct OnBoardingSample: View {
let onboardingTitle: String
let imageSystemName: String
var body: some View {
ZStack {
Color.gray.ignoresSafeArea()
VStack {
Image(systemName: imageSystemName)
.resizable()
.scaledToFit()
.frame(width: 100)
.foregroundColor(.white)
Text(onboardingTitle)
.padding()
.font(/*@START_MENU_TOKEN@*/.title/*@END_MENU_TOKEN@*/)
.foregroundColor(.white)
}
}
}
}
#Preview {
OnBoardingSample(onboardingTitle: "This is Detail!", imageSystemName: "square.and.arrow.up")
}
버튼이 있는 마지막 모달 페이지는 다음과 같은 작업을 추가로 하면 된다.
1. 메인 화면에서 온보드 패널들이 보여지고 있는지를 뜻하는 bool 변수를 바인딩
2. VStack 안에 버튼 생성 후, 위의 바인딩한 변수의 값을 true로 변경
3. 해당 파일 생성자에 bool 변수에 대한 초기값을 .constant(true)로 설정

OnBoard의 하단에 페이지의 개수와 현재 위치를 보여주기 위해서는 indexDisplayMode의 설정을 다음과 같이 하면 된다.
.tabViewStyle(.page(indexDisplayMode: .always))
앱을 생성할 메인 파일에서는 다음과 같이 작성한다.
struct MyApp: View {
@State var showModal = false
var body: some View {
TabView {
// Received
// Send
// Account
}
.sheet(isPresented: $showModal, content: {
TabView {
OnBoardingSample(onboardingTitle: "OnBoard 1", imageSystemName: "1.lane")
OnBoardingSample(onboardingTitle: "OnBoard 2", imageSystemName: "2.lane")
OnBoardingWithButton(isPresented: $showModal, onboardingTitle: "OnBoard 3", imageSystemName: "3.lane")
}
.tabViewStyle(.page(indexDisplayMode: .always))
})
.onAppear() {
showModal = true
}
}
}
하단에 탭을 생성하기 위한 코드다. 위 TabView의 경우 설정을 따로 했지만, 기본적으로는 하단에 탭뷰 아이템들이 순서대로 그려진다.
struct MyApp: View {
@State var showModal = false
var body: some View {
TabView {
// 추후 List 페이지로 수정
Text("Received")
.tabItem {
Label("Received", systemImage: "tray.and.arrow.down.fill")
}
Text("Send")
.tabItem {
Label("Send", systemImage: "tray.and.arrow.up.fill")
}
Text("Account")
.tabItem {
Label("Account", systemImage: "person.crop.circle.fill")
}
}
.sheet(isPresented: $showModal, content: {
TabView {
OnBoardingSample(onboardingTitle: "OnBoard 1", imageSystemName: "1.lane")
OnBoardingSample(onboardingTitle: "OnBoard 2", imageSystemName: "2.lane")
OnBoardingWithButton(isPresented: $showModal, onboardingTitle: "OnBoard 3", imageSystemName: "3.lane")
}
.tabViewStyle(.page(indexDisplayMode: .always))
})
.onAppear() {
showModal = true
}
}
}

Navigation Stack과 List를 활용해 Navigation Link를 순서대로 담는다. Navigation Link를 클릭하면 그에 대한 subpage가 나타난다.
struct FirstListPage: View {
var body: some View {
NavigationStack {
List {
NavigationLink {
Text("First Subpage")
} label: {
Text("First")
}
NavigationLink {
Text("Second Subpage")
} label: {
Text("Second")
}
NavigationLink {
Text("Third Subpage")
} label: {
Text("Third")
}
NavigationLink {
Text("Fourth Subpage")
} label: {
Text("Fourth")
}
}
.navigationTitle("Received")
}
}
}
이렇게 생성한 List Page를 불러오기 위해 메인 화면의 Received 부분의 내용을 다음과 같이 변경한다.
FirstListPage().tabItem { Label("Received", systemImage: "tray.and.arrow.down.fill") }
위 링크에서 구현한 화면의 결과물을 확인해보자.