NavigationStack vs NavigationView in SwiftUI
SwiftUI is a modern framework for building user interfaces for Apple platforms. It includes a lot of features to create complex user interfaces, including navigation. Navigation is an essential part of any app, and SwiftUI provides two ways to implement navigation: NavigationStack and NavigationView.
Note: As of iOS16 and above, NavigationView is deprecated and replaced with NavigationStack
To start, we will examine how NavigationView is implemented. Next, we will look at an example of how NavigationStack is implemented. Finally, we will discuss the various uses of each in the conclusion section.
NavigationView works in conjunction with NavigationLink by wrapping the content of the views, allowing users to link the next view.
NavigationLink performs the task of assigning next view which is to be presented.
In the example below we add NavigationView to the list of cars and each item for the list is linked via NavigationLink which presents
CarDetailView when tapped on a particular list item.
This is one of the simplest ways to handle navigation in SwiftUI for iOS 15 and below. (More info)
The new containers in SwiftUI provide a simpler way to implement navigation flows. With the introduction of NavigationStack in iOS 16+, we can now manage the stack state/path of our views with a single binding. This means that we no longer need to create individual views for each screen in the navigation flow, making our code more concise and easier to maintain. Instead, we can use the NavigationStack to create a stack of views that can be pushed and popped to navigate between them. This provides a more streamlined approach to navigation, reducing the complexity of our code and making it easier to manage.
NavigationLinks can still be used with NavigationStack just like you would with NavigationView.
Below is an example of primary-detail flow for presenting detail of the car using of simple NavigationStack with NavigationLink. This works similar to NavigationViews and can be used as an initial solution while transitioning from NavigationView to NavigationStack with minimal change to the code.
With iOS 16, a new API for
NavigationLink is available, which allows us to append values to the binding. These bindings can then be used by
NavigationDestination to present the next view.
We have refactored the code above, allowing us to create links bound to the
value (e.g., "car") using the new NavigationLinks API. The
value must conform to
Hashable and works in conjunction with
navigationDestination to attach a destination for the value.
Additionally, the navigationDestination can be modified to refactor the code above by allowing multiple navigationDestination view modifiers for different value types, such as car or car type. In the example below, we will add another view, CarTypeView, for the type of car. With two value types, we can bind the view modifiers to their own navigationDestination for a cleaner and more organized flow.
While NavigationView is a simpler approach to navigation in SwiftUI than setting up
UINavigationController in iOS, it still requires some tweaks. This is where NavigationStack comes in, with its clean approach to better NavigationLinks and better handling of destination links.
Since SwiftUI is still evolving and many apps might still be using NavigationView, the best way forward for somewhat backwards compatibility is to wrap both navigation styles inside a
NavHandler can then be used in any view as shown below. However, this approach may have drawbacks if you want to use newer APIs for NavigationLink. Nonetheless, it is a way to adapt to the new NavigationStack