SwiftUI 4 New Navigation API

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:

  • iOS
  • iPadOS
  • MacOS
  • Mac Catalyst
  • tvOS
  • watchOS

Instead, SwiftUI 4 provides a couple of different views depending on your use case.

NavigationStack

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")
                ]
            )
        }
    }
}

NavigationSplitView

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

Subscribe To The Newsletter

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