WWDC22 brings a lot of welcome improvements to SwiftUI and in this blog post I will talk about improvements to the Navigation API.
Posted By Adam Bulmer In SwiftUI
Starting with SwiftUI 4, the NavigationView has been deprecated across the following Platforms:
Instead, SwiftUI 4 provides a couple of different views depending on your use case.
A view that displays a root view and enables you to present additional views over the root view.
This view has been designed to be a direct replacement for the NavigationView and by default can be used in the same way just by replacing NavigationView
with NavigationStack
.
struct ContentView: View {
var body: some View {
NavigationStack {
NavigationLink {
Text("MyCustomView")
} label: {
Text("Navigation Item 1")
}
.navigationTitle("Navigation Title")
}
}
}
NavigationStack
provides us with alternative ways to manage the navigation within our apps allowing us to deep-link and programmatically update our navigation stacks.
struct ContentView: View {
var todos: [Todo] = [
Todo(id: UUID(), name: "Watch WWDC22 Videos"),
Todo(id: UUID(), name: "Write WWDC22 Articles")
]
var body: some View {
NavigationStack {
List(todos) { todo in
NavigationLink(todo.name, value: todo)
}
.navigationDestination(for: Todo.self) { todo in
Text("\(todo.name)")
.navigationTitle(todo.name)
}
}
}
}
The NavigationLink
now has a new initialiser that binds a value
to a NavigationLink
. SwiftUI 4 also provides a navigationDestination
view modifier that allows us to provide a detail view for the bound value. This decouples the navigation destination from the navigation link.
If you have done any web development you will know every web page is based on a route. With iOS 16, Apple has created a similar model providing us the ablity to progmatically set the route path.
To enable this route based functionality, You can call the NavigationStack
initialiser with a binding to an array (stack) of values.
By altering the array, the navigation will update automatically.
struct ContentView: View {
var todos: [Todo] = [
Todo(id: UUID(), name: "Watch WWDC Videos"),
Todo(id: UUID(), name: "Write WWDC Articles")
]
@State var currentPath: [Todo] = []
var body: some View {
NavigationStack(path: $currentPath) {
List {
ForEach(todos) { todo in
NavigationLink(todo.name, value: todo)
}
}
.navigationTitle("Todolist")
.navigationDestination(for: Todo.self) { todo in
Text("\(todo.name)")
.navigationTitle(todo.name)
}
}
.onOpenURL {
currentPath.append(
contentsOf: [
Todo(id: UUID(), name: "Deeplink Parent Video"),
Todo(id: UUID(), name: "Deeplink Child View")
]
)
}
}
}
A view that presents views in two or three columns, where selections in leading columns control presentations in subsequent columns.
What is great with the NavigationSplitView
is on smaller screen sizes, it will behave exactly like the NavigationStack
which is useful when targetting multiple platforms like iOS and iPadOS.
struct ContentView: View {
var rooms: [String] = ["Living Room", "Kitchen", "Dining Room", "Bedroom"]
@State private var room: String?
var body: some View {
NavigationSplitView {
List(rooms, id: \.self, selection: $room) { room in
Text(room)
}
} detail: {
Text(room ?? "Please Select A Room")
}
}
}
If you want to create your first native app or have just begun your native app development journey, be sure to sign up to the newsletter. No Spam