iOS
웹개발자의 iOS 개발기(7) - [SwiftUI] 모달, 네비게이션, 탭뷰
whh__
2025. 1. 26. 01:09
모달, 네비게이션, 탭뷰에 대하여 공부해 보았습니다.
01. 여러 화면을 이동하기
Modal
import SwiftUI
struct _1_Modal: View {
@State var showModal: Bool = false
var body: some View {
VStack {
Text("메인 페이지 입니다.1")
Button {
showModal = true
} label: {
Text("Modal 화면 전환")
}
}
.sheet(isPresented: $showModal) {
_1_Detail(isPresented: $showModal)
}
}
}
#Preview {
_1_Modal()
}
Detail
import SwiftUI
struct _1_Detail: View {
@Binding var isPresented: Bool
var body: some View {
Text("모달 페이지 입니다.2")
Button {
isPresented = false
} label: {
Text("닫기")
}
}
}
#Preview {
_1_Detail(isPresented: .constant(true))
}
@Binding
- 부모뷰에서 자식뷰에 데이터를 전달할 때 사용
- 부모뷰가 상태값을 소유하고, 자식뷰가 이를 수정해야 할 경우 사용
@Binding 주의점
- 상태 소유는 부모에서만: 자식 뷰는 상태를 소유하지 않습니다. @Binding은 항상 부모에서 소유한 상태를 참조한다.
- 데이터 흐름: SwiftUI는 단방향 데이터 흐름(Unidirectional Data Flow)을 기반으로 설계되었다. @Binding은 이 흐름을 해치지 않고 데이터 수정 권한을 자식에게 잠시 위임하는 역할을 한다.
- 값이 없는 경우 처리: 만약 부모 뷰가 상태를 제공하지 않으면 런타임 에러가 발생한다. 이를 방지하려면 적절히 상태를 초기화해야 한다.
02. 네비게이션 써보기
NavigationStack, NavigationLink, toolbar 사용해 보기
import SwiftUI
struct _2_Navigation: View {
let titles = ["디테일뷰로 이동하기", "디테일뷰로 이동하기2"]
let descriptions = ["데스티네이션 입니다.", "데스티네이션 입니다.2"]
@State var showModal: Bool = false
var body: some View {
NavigationStack {
List {
ForEach([0,1], id: \\.self) { index in
NavigationLink {
Text(descriptions[index])
} label : {
Text(titles[index])
}
}
}
.toolbar{
ToolbarItem(placement: .automatic) {
Button {
showModal = true
} label: {
Text("Add")
}
}
}
.sheet(isPresented: $showModal, content: {
Text("아이템 추가 페이지 입니다.")
})
.navigationTitle("네비게이션")
}
}
}
#Preview {
_2_Navigation()
}
03. 탭뷰로 그려보기
import SwiftUI
struct _3_MyTab: View {
var body: some View {
TabView {
//_3_TabDetail()
_4_OnBoarding()
.badge(2)
.tabItem {
Label("Received", systemImage: "tray.and.arrow.down.fill")
}
//_3_TabDetail2()
Text("Sent 화면입니다.")
.badge(2)
.tabItem {
Label("Sent", systemImage: "tray.and.arrow.up")
}
//_3_TabDetail3()
Text("Account 화면입니다.")
.badge("!")
.tabItem {
Label("Account", systemImage: "person.crop.circle.fill")
}
}
//.tabViewStyle(.page(indexDisplayMode: .always))
}
}
#Preview {
_3_MyTab()
}
04. 여러 개의 화면을 이어서 만든 앱
import SwiftUI
struct _4_MyApp: View {
@State var showModal: Bool = false
var body: some View {
TabView {
_4_List()
.tabItem {
Label("first", systemImage: "tray.and.arrow.down.fill")
}
Text("두번째 페이지")
.tabItem {
Label("second", systemImage: "tray.and.arrow.down.fill")
}
Text("세번째 페이지")
.tabItem {
Label("third", systemImage: "tray.and.arrow.down.fill")
}
Text("네번째 페이지")
.tabItem {
Label("fourth", systemImage: "tray.and.arrow.down.fill")
}
}
.sheet(isPresented: $showModal, content: {
TabView {
_4_OnBoarding1(onboardingTitle: "온보딩 1", backgroundColor: .blue)
_4_OnBoarding1(onboardingTitle: "온보딩 2", backgroundColor: .green)
_4_OnBoarding1(onboardingTitle: "온보딩 3", backgroundColor: .yellow)
ZStack {
Color.gray.ignoresSafeArea()
VStack {
Text("온보딩4")
Button {
showModal = false
} label: {
Text("Start")
}
}
}
}
.tabViewStyle(.page)
})
.onAppear {
showModal = true
}
}
}
#Preview {
_4_MyApp()
}