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()
}

 

간단한 앱 구조