-
Notifications
You must be signed in to change notification settings - Fork 0
/
NavigationBootcamp.swift
291 lines (252 loc) · 13.1 KB
/
NavigationBootcamp.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
//
// NavigationBootcamp.swift
// SwiftfulThinkingBootcamp
//
// Created by enesozmus on 11.05.2024.
//
import SwiftUI
struct NavigationBootcamp: View {
@State private var showDetails = false
@State var path: [String] = ["1", "2", "3"]
@State var paths = NavigationPath(["1", "2"])
var body: some View {
NavigationStack {
ScrollView {
NavigationLink("This is screen number 1") {
Text("Go to screen 1")
}
Spacer().frame(height: 10)
NavigationLink("This is screen number 2") {
Text("Go to screen 2")
}
}
.navigationTitle("Screens")
.navigationBarTitleDisplayMode(.automatic)
.toolbar {
ToolbarItemGroup(placement: .navigationBarLeading) {
Button {
} label: {
Image(systemName: "person.fill")
}
}
ToolbarItemGroup(placement: .navigationBarTrailing) {
Button {
} label: {
Image(systemName: "gear")
}
}
}
}
// NavigationStack {
// List {
// NavigationLink("Mint", value: Color.mint)
// NavigationLink("Pink", value: Color.pink)
// NavigationLink("Teal", value: Color.teal)
// }
// .navigationDestination(for: Color.self) { color in
// ColorDetail(color: color)
// }
// .navigationTitle("Colors")
// }
// NavigationStack {
// VStack {
// Button("Update detail") {
// showDetails = true
// }
// }
// .navigationDestination(isPresented: $showDetails) {
// VStack {
// Text("Deails was updated")
// Button("close") {
// showDetails = false
// }
// }
// }
// }
// NavigationStack(path: $path) {
// VStack {
// NavigationLink("Go to screen 4", value: "4")
// }
// .navigationDestination(for: String.self) { value in
// Text("This is screen number \(value)")
// }
// }
// NavigationStack(path: $paths) {
// VStack {
// NavigationLink("Go to int screen", value: 1)
// Spacer().frame(height: 10)
// NavigationLink("Go to person screen", value: PersonModel(name: "Mark", age: 32))
//
// }
// .navigationDestination(for: String.self) { value in
// Text("This is a string screen with value: \(value)")
// }
// .navigationDestination(for: Int.self) { value in
// Text("This is a int screen with value: \(value)")
// }
// .navigationDestination(for: PersonModel.self) { value in
// Text("This is a int Person with,\nName: \(value.name), Age: \(value.age)")
// }
// }
}
}
struct ColorDetail: View {
var color: Color
var body: some View {
color.navigationTitle(color.description)
}
}
struct PersonModel: Hashable {
let name: String
let age: Int
}
#Preview {
NavigationBootcamp()
}
/*
https://developer.apple.com/documentation/swiftui/navigation
https://developer.apple.com/documentation/swiftui/navigationstack
https://medium.com/@fsamuelsmartins/how-to-use-the-swiftuis-navigationstack-79f32ada7c69
🔴 Navigation
→ Navigation in SwiftUI is a powerful tool for creating complex and dynamic user interfaces.
→ Whether you’re building a simple prototype or a full-fledged application, SwiftUI’s navigation tools can help you create the perfect user experience.
→ Navigation was done using NavigationView, but it was deprecated in iOS 16 and was split into two new containers, NavigationStack and NavigationSplitView, and each one of them has new features.
→ Enable people to move between different parts of your app’s view hierarchy within a scene.
→ Use navigation containers to provide structure to your app’s user interface, enabling people to easily move among the parts of your app.
🔴 NavigationStack
→ A view that displays a root view and enables you to present additional views over the root view.
→ NavigationStack is used to set the view in a succeeding navigation, stacking the new view over the previous one, always having one view on top.
→ The stack always displays the most recently added view that hasn’t been removed, and doesn’t allow the root view to be removed.
→ Use a NavigationStack to present a stack of views over a root view.
→ Add views to the top of the stack by clicking or tapping a NavigationLink
→ Remove views using built-in, platform-appropriate controls, like a Back button or a swipe gesture.
→ To create navigation links, associate a view with a data type by adding a navigationDestination(for:destination:) modifier inside the stack’s view hierarchy.
🟩
NavigationStack {
List(parks) { park in
NavigationLink(park.name, value: park)
}
.navigationDestination(for: Park.self) { park in
ParkDetails(park: park)
}
}
🟩
NavigationStack {
VStack {
NavigationLink("This is screen number 1") {
Text("Go to screen 1")
}
Spacer().frame(height: 10)
NavigationLink("This is screen number 2") {
Text("Go to screen 2")
}
}
}
🔴 navigationDestination(for:destination:)
→ The new navigation system made the code cleaner because now is possible to define the destination apart from NavigationLink creation.
→ To define the destination, you need to add to the father view of the NavigationLink, the function navigationDestination(), that has the following parameters:
→ Associates a destination view with a presented data type for use within a navigation stack.
→ Add this view modifer to a view inside a NavigationStack to describe the view that the stack displays when presenting a particular kind of data.
→ Use a NavigationLink to present the data.
Parameters:
-> Data: The type of data that this destination matches. This parameter only accepts values that implement the Hashable protocol.
-> Destination: A view builder that defines a view to display when the stack’s navigation state contains a value of type data. The closure takes one argument, which is the value of the data to present.
🟩
NavigationStack {
List {
NavigationLink("Mint", value: Color.mint)
NavigationLink("Pink", value: Color.pink)
NavigationLink("Teal", value: Color.teal)
}
.navigationDestination(for: Color.self) { color in
ColorDetail(color: color)
}
.navigationTitle("Colors")
}
🟩
NavigationStack {
VStack {
NavigationLink("Go to screen 1", value: "1")
Spacer().frame(height: 10)
NavigationLink("Go to screen 2", value: "2")
}
.navigationDestination(for: String.self) { value in
Text("This is screen number \(value)")
}
}
🔴 NavigationDestination for a boolean state variable
→ Another way of implementing the navigation destination is observing a boolean state variable, so, every time the observable state is changed, the destination will be triggered.
Parameters:
-> isPresented: A binding to a Boolean value that indicates whether destination is currently presented.
-> destination: A view to present.
struct ContentView: View {
@State private var showDetails = false
var body: some View {
NavigationStack {
VStack {
Button("Update detail") {
showDetails = true
}
}
.navigationDestination(isPresented: $showDetails) {
VStack {
Text("Deails was updated")
Button("close") {
showDetails = false
}
}
}
}
}
}
🔴 NavigationStack path parameter
→ This new parameter is one of the best new features that came in iOS 16, this allows an easier implementation of deeplinks and other specific cases of navigation.
→ Basically, this parameter allows us to define a predefined route to the new destination, and to track all stacked screens in the path.
→ Each item in this list corresponds to a screen that will be open when the program starts.
struct ContentView: View {
@State var path: [String] = ["1", "2", "3"]
var body: some View {
NavigationStack(path: $path) {
VStack {
NavigationLink("Go to screen 4", value: "4")
}.navigationDestination(for: String.self) { value in
Text("This is screen number \(value)")
}
}
}
}
🔴 NavigationPath
→ In the previous topic, a list of Strings was created to be the path variable of NavigationStack, but what should be done if one new screen needs to receive other type as its parameter, and we still want to track all the navigation?
→ Apple has created a type-erased list of data to resolve this problem, this list is called NavigationPath.
→ For a better example of how to use the NavigationPath, we will create a person model, and like the value parameter of the NavigationLink, every type that will be added to the path list needs to implement the Hashable protocol.
struct PersonModel: Hashable {
let name: String
let age: Int
}
→ Then, we create a NavigationPath with two starting paths with the type String.
→ After that, the new path is set at the NavigationStack's path parameter, and now to test the type flexibility of the NavigationPath, we're going to make two new NavigationsLinks with different types.
→ The first link has an integer as in it value parameter, and the second one uses the created person model as the value. After adding the different types of value, we need to define the specific destination for them.
struct ContentView: View {
@State var path = NavigationPath(["1", "2"])
var body: some View {
NavigationStack(path: $path) {
VStack {
NavigationLink("Go to int screen", value: 1)
Spacer().frame(height: 10)
NavigationLink("Go to person screen", value: PersonModel(name: "Mark", age: 32))
}
.navigationDestination(for: String.self) { value in
Text("This is a string screen with value: \(value)")
}
.navigationDestination(for: Int.self) { value in
Text("This is a int screen with value: \(value)")
}
.navigationDestination(for: PersonModel.self) { value in
Text("This is a int Person with,\nName: \(value.name), Age: \(value.age)")
}
}
}
}
🔴 NavigationSplitView
→ NavigationSplitView, is used when you need to make a column base navigation. So, the screen will be divided into columns, where each column is one subview of NavigationSplitView.
*/