NavigationLink is a view which controls a navigation presentation. NavigationLink was introduced in iOS 13. Starting iOS 16, there is a slight difference in navigation presentation with the introduction of NavigationStack and NavigationSplitView.
In this article, we will look at NavigationLink for navigation presentation supported from iOS 13 to iOS 15 and navigation presentation for iOS 16+.
Navigation Presentation in iOS 13 to iOS 15(prior iOS 16)
NavigationLink is a view which commands the enclosing NavigationView to push another view into the navigation stack. NavigationLink takes destination and label as parameter for one of its initializer.
destination: is a ViewBuilder which provides the view that will be pushed into the NavigationView.
label: is the view which can be tapped to trigger the navigation command.
struct DevTechieNavigationLinkExample: View {
var body: some View {
NavigationView {
VStack {
Text("Hello, DevTechie")
.font(.largeTitle)
NavigationLink(destination: Text("You reached here via NaviagtionLink")) {
HStack {
Image(systemName: "computermouse")
Text("Click Me!")
}
}
.padding()
}
}
}
}
Note that we are using a Text view as destination for our example but SwiftUI presents entire view along with back button to complete the experience.
We can build entire experience inside the ViewBuilder. Here is an example but you get the point.
When view is pushed into the navigation stack, setting navigationTitle is as easy as adding as a modifier. We don’t need another NavigationView to set navigation title at the destination view.
Let’s update our example to include navigation title for both main view and destination view.
Notice that the NavDestinationView’s body doesn’t contain NavigationView.
Programmatic navigation is possible with the help of another overload which takes isActive binding value as a parameter. IsActive is a boolean binding that if toggled to true, triggers the navigation.
We will replace NavigationLink to the overload which takes isActive param and add a button which will trigger programmatic navigation.
struct DevTechieNavigationLinkExample: View {
@State private var triggerNavigation = false
var body: some View {
NavigationView {
VStack {
Text("Hello, DevTechie")
.font(.largeTitle)
NavigationLink("Click Me!", destination: NavDestinationView(), isActive: $triggerNavigation)
.padding()
Button("Click me to navigate") {
triggerNavigation.toggle()
}
.buttonStyle(.borderedProminent)
}
.navigationTitle("DevTechie.com")
}
}
}
Note: Both navigation link and button will trigger the navigation push command. triggerNavigation parameter resets to false value when back button is tapped on the detail view.
NavigationLink provides a value binding overload as well. NavigationLink takes selection as a parameter which is a binding value and when it matches the tag parameter, linked view is pushed into the navigation stack.
We will add three NavigationLinks and three Buttons to trigger the navigation, link corresponding to the button will issue the navigation command.
If the navigation bar is hidden, we can use dismiss environment variable to dismiss the detail view.
Let’s hide navigation bar from detail view and add Environment variable. Starting iOS 15, new environment variable called dismiss has been introduced but if you are supporting version prior that, you will have to use presentationModeenvironment variable.
Prior iOS 15:
struct NavDestinationView: View {
@Environment(\.presentationMode) var presentationMode
var viewName: String
var body: some View {
VStack {
Text(viewName)
Text("Hello DevTechie!")
.font(.largeTitle)
.foregroundColor(.white)
.padding()
.background(Color.orange, in: RoundedRectangle(cornerRadius: 20))
Text("Welcome to the \(viewName)!")
.font(.title)
Text("Let's learn and grow together!")
Button("Dismiss") {
presentationMode.wrappedValue.dismiss()
}
.buttonStyle(.borderedProminent)
.tint(.red)
}
.navigationBarHidden(true)
.navigationTitle("NavDestination View")
}
}
iOS 15 and above:
struct NavDestinationView: View {
@Environment(\.dismiss) var dismiss
var viewName: String
var body: some View {
VStack {
Text(viewName)
Text("Hello DevTechie!")
.font(.largeTitle)
.foregroundColor(.white)
.padding()
.background(Color.orange, in: RoundedRectangle(cornerRadius: 20))
Text("Welcome to the \(viewName)!")
.font(.title)
Text("Let's learn and grow together!")
Button("Dismiss") {
dismiss()
}
.buttonStyle(.borderedProminent)
.tint(.red)
}
.navigationBarHidden(true)
.navigationTitle("NavDestination View")
}
}
Navigation Presentation in iOS 16 and above
With iOS 16 came NavigationStack and to create a presentation link within NavigationStack we use navigationDestination(for:destination:) modifier. This modifier associates a view with a kind of data and then presents value of that data type from a navigationLink.
Starting iOS 16, NavigationLink takes value as a parameter. Value is an optional value to present. When someone taps or clicks the link, SwiftUI stores a copy of the value. Value is received as a closure parameter in navigationDestinationclosure.
struct DevTechieNavigationLinkExample: View {
var body: some View {
NavigationStack {
VStack {
Text("DevTechie")
.font(.largeTitle)
NavigationLink("Next page", value: "New Detail View")
}
.navigationDestination(for: String.self) { val in
NavDestinationView(viewName: val)
}
}
}
}
navigationDestination simplifies the navigation strategy by facilitating programmatic navigation because now we can manager navigation state by recording the presented data.
Value is not limited to primitive types only but any type conforming to Hashable protocol can be used with NavigationStack.
Let’s create our own type.
struct DevTechieCourse: Identifiable, Hashable {
let id = UUID()
let name: String
}extension DevTechieCourse {
static var exampleData: [DevTechieCourse] {
return [
.init(name: "Mastering SwiftUI"),
.init(name: "Build Disney Plus Clone in SwiftUI"),
.init(name: "Build Video Player App in SwiftUI"),
.init(name: "Build Drawing App in SwiftUI")
]
}
}
Next let’s use NavigationStack, NavigationLink and navigationDestination in a List view.
struct DevTechieNavigationLinkExample: View {
var body: some View {
NavigationStack {
List(DevTechieCourse.exampleData) { course in
NavigationLink(course.name, value: course)
}
.listStyle(.plain)
.navigationTitle("DevTechie Courses")
.navigationDestination(for: DevTechieCourse.self) { course in
Text(course.name)
}
}
}
}
With that we have reached the end of this article. Thank you once again for reading. If you liked this, don’t forget to 👏 and follow 😍. Also subscribe to our weekly newsletter at https://www.devtechie.com