기어가더라도 제대로
[SwiftUI-기초] NavigationStack 알아보기 본문
개념
iOS 16 이후에 제안된 화면 전환 로직을 담당하는 뷰
- 루트 뷰 위에 스택 처럼 화면을 쌓는다 해서 Stack
- 특징: 가장 상위 화면까지 오는 그 흐름을 추적 가능
- 한번에 스택의 어떤 화면으로 이동 가능해 딥링크 같은 기술에 응용 가능
path라는 개념을 도입하고, View와 Data를 엮어서 추적하는 방식을 사용
같은 데이터 타입끼리의 화면 이동
화면이 쌓이는 경우를 추적하지 않는다하면, NavigationStack(root:)로 이니셜라이징
추적을 한다면 NavigationStack(path:,root:)로 이니셜라이징
이 예제에서는 숫자를 표시해주는 NumberView를 쌓음
- 화면이 쌓이는 것을 추적하기 위해 presentedNumbers 추가
struct ContentView: View {
@State private var presentedNumbers: [Int] = []
var body: some View {
Text("Hello world")
}
}
- 네비게이션 스택과 간단한 유아이를 그림, 리스트로 1~10까지의 숫자를 표현하고, 마지막엔 버튼을 추가
NavigationStack(path: $presentedNumbers) {
VStack {
List(0..<numbers.count, id: \.self) { index in
let number = numbers[index]
NavigationLink("\(number)", value: number)
}
}
Button("make 1,7,10 stack") {
stackOneSevenTen()
}
}
이 코드가 의아하게 느껴짐. 이전에 화면 조작을 해보았다면 NavigationLink에 목적지를 같이 지정했던 것을 기억해서 일테니까.
- 이것을 위해 .navigationDestination 이라는 뷰 수정자를 선언
NavigationStack(path: $presentedNumbers) {
VStack {
List(0..<numbers.count, id: \.self) { index in
let number = numbers[index]
NavigationLink("\(number)", value: number)
}
.navigationDestination(for: Int.self) { number in
NumberView(
presentedNumbers: $presentedNumbers,
number: number
)
}
}
Button("make 1,7,10 stack") {
stackOneSevenTen()
}
}
화면과 데이터를 엮기 때문에, Int.self로 value에 number가 추가되었을 때 인식하고 목적지로 추가함
참고로 .navigationDestination 뷰 수정자는 NavigationStack 의 중괄호 함수 안에만 있으면 유효
- 딥링크를 예시로 하기 위해서 화면을 1번, 7번, 10번을 쌓는 함수
func stackOneSevenTen() {
presentedNumbers = [1,7,10]
}
- 보여질 NumberView, 이 화면이 나타나면서 현재 어떤 숫자가 쌓였는지 알려줌
struct NumberView: View {
@Binding var presentedNumbers: [Int]
let number: Int
var body: some View {
Text("지금은 \(number) 뷰입니다.")
.onAppear {
print(presentedNumbers)
}
}
}
- 구현 화면, NumberView가 등장할 때마다 Path에 어떤 화면이 쌓였는지 추적
- 여러화면을 한번에 로드할 때는 처음 로드하는 시점에만 Init이 되고 뒤로가기 버튼이 눌렸을 때는 init이 안되는 것을 확인 가능
다른 데이터 타입의 화면 이동을 추적
살다보면 여러 과일을 한 바구니에 담고 싶어질 때도 있음, 과일 선물 세트가 있는 이유이기도 함
NavigationPath: 타입 지우개를 통해서 한 변수가 모든 데이터 타입을 받을 수 있되, 화면 이동을 추적하는 용도로만 쓸 수 있게 함
struct ContentView: View {
@State var presentedValues: NavigationPath
let numbers = [1,2,3,4,5]
let words = ["a","b","c","d","e"]
- 화면을 하나의 List에서 두 개의 ForEach로 나눔
var body: some View {
NavigationStack(path: $presentedValues) {
List {
ForEach(0..<numbers.count, id: \.self) { index in
let number = numbers[index]
NavigationLink("\(number)", value: number)
}
ForEach(0..<words.count, id: \.self) { index in
let word = words[index]
NavigationLink("\(word)", value: word)
}
}
- 위에 반복문은 숫자를 표현하고, 아래는 글자를 표현함
List { ~ }
.navigationDestination(for: Int.self) { number in
NumberView(
presentedValues: $presentedValues,
number: number
)
}
.navigationDestination(for: String.self) { word in
StringView(
presentedValues: $presentedValues,
word: word
)
}
- 글자를 표시하는 화면
struct StringView: View {
@Binding var presentedValues: NavigationPath
let word: String
var body: some View {
Text("지금은 \(word) 뷰입니다.")
.onAppear {
print(presentedValues)
}
}
}
- 완성된 모습
전체 코드
https://gist.github.com/Damagucci-Juice/42bc0fabf18f437ec6edc2c1612a0090
NavigationStack 예시
NavigationStack 예시. GitHub Gist: instantly share code, notes, and snippets.
gist.github.com
참조
https://developer.apple.com/documentation/swiftui/navigationpath
NavigationPath | Apple Developer Documentation
A type-erased list of data representing the content of a navigation stack.
developer.apple.com
https://developer.apple.com/documentation/swiftui/navigationstack
NavigationStack | Apple Developer Documentation
A view that displays a root view and enables you to present additional views over the root view.
developer.apple.com
'SwiftUI - 기초' 카테고리의 다른 글
[SwiftUI-기초] MVVM과 SwiftUI 근데 Combine을 곁들인 (0) | 2025.02.12 |
---|---|
[SwiftUI-기초] @Published 프로퍼티의 데이터 동기화 하는 방법 (0) | 2025.01.24 |
[SwiftUI-기초] NavigationTitle 수동으로 inline 만들기(with. ToolbarItem) (0) | 2025.01.23 |
[SwiftUI-기초] 프로젝트에서 TabView 두개 사용하기(Multiple TabView) (0) | 2025.01.22 |
[SwiftUI-기초] 수직 확장 되는 텍스트 필드, TextField, TextEditor (0) | 2025.01.20 |