Using NavigationView and NavigationLink in SwiftUI: Basics, Customizations, and Advanced Techniques
This article explains how to use SwiftUI's NavigationView and NavigationLink for page navigation, covering basic setup, title bar customization, hiding the navigation bar, programmatic back actions, button style adjustments, advanced gestures, the isActive parameter, and dynamic navigation link generation for iOS apps.
In UIKit developers often use UINavigationViewController to manage page push and pop operations. In SwiftUI the same functionality is provided by NavigationView and NavigationLink.
Basic Concept
The following demo shows the simplest use of NavigationView and NavigationLink:
import SwiftUI
@main
struct iOS_testApp: App {
var body: some Scene {
WindowGroup {
NavigationView {
NavigationLink(
destination: Text("Destination"),
label: {
Text("Navigate")
})
}
}
}
}Here NavigationView acts as the top‑level container similar to UINavigationViewController in UIKit, while NavigationLink defines the view to be pushed when the user taps the label.
Setting the Title Bar
By default the root view of a NavigationView has no title bar, but the pushed view shows a back bar with an empty title. Use the .navigationBarTitle modifier to set a title:
import SwiftUI
@main
struct iOS_testApp: App {
var body: some Scene {
WindowGroup {
NavigationView {
NavigationLink(
destination: Text("Destination"),
label: { Text("Navigate") })
.navigationBarTitle("Main", displayMode: .large)
}
}
}
}The displayMode enum can be .inline, .large or .automatic, the latter letting the system choose the appropriate style.
Hiding the Title Bar
If you want to hide the navigation bar completely, apply .navigationBarHidden(true):
import SwiftUI
@main
struct iOS_testApp: App {
var body: some Scene {
WindowGroup {
NavigationView {
NavigationLink(
destination: Text("Destination")
.navigationBarHidden(true),
label: { Text("Navigate") })
.navigationBarTitle("Main", displayMode: .automatic)
}
}
}
}Programmatic Back Logic
When the title bar is hidden, the default back button disappears. Use the environment variable @Environment(\.presentationMode) to dismiss the view manually:
import SwiftUI
struct DestinationView: View {
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
var body: some View {
Text("Destination View")
.navigationBarHidden(true)
.onTapGesture { self.presentationMode.wrappedValue.dismiss() }
}
}
struct ContentView: View {
var body: some View {
NavigationView {
NavigationLink(destination: DestinationView()) {
Text("Navigate View")
}
}
}
}
@main
struct iOS_testApp: App {
var body: some Scene {
WindowGroup { ContentView() }
}
}Title Bar Style
Global appearance can be changed with UINavigationBar.appearance(). For example, to make the title red:
struct ContentView: View {
var body: some View {
NavigationView {
NavigationLink(destination: DestinationView()) {
Text("Navigate View")
}
.navigationBarTitle("Title", displayMode: .inline)
.onAppear {
UINavigationBar.appearance().titleTextAttributes = [.foregroundColor: UIColor.red]
}
}
}
}Removing Default Button Effects
The default button style adds a blue highlight. Define a custom ButtonStyle that clears the background:
struct DefaultButtonStyle: ButtonStyle {
func makeBody(configuration: Self.Configuration) -> some View {
configuration.label
.background(configuration.isPressed ? Color.clear : Color.clear)
}
}Apply it to the navigation link:
struct ContentView: View {
var body: some View {
NavigationView {
NavigationLink(destination: DestinationView()) {
Text("Navigate View")
}
.navigationBarTitle("Title", displayMode: .inline)
.buttonStyle(DefaultButtonStyle())
.onAppear {
UINavigationBar.appearance().titleTextAttributes = [.foregroundColor: UIColor.red]
}
}
}
}Advanced Gestures: Tap and Long‑Press
Combine onTapGesture and onLongPressGesture on the label to support both interactions while preserving navigation:
struct ContentView: View {
var body: some View {
NavigationView {
NavigationLink(destination: DestinationView()) {
Text("Navigate View")
.onTapGesture { print("tap") }
.onLongPressGesture { print("long press") }
}
}
}
}When using a custom isActive binding, the tap gesture can set the binding to true to trigger navigation:
struct ContentView: View {
@State private var isActive = false
var body: some View {
NavigationView {
NavigationLink(destination: DestinationView(), isActive: $isActive) {
Text("Navigate View")
.onTapGesture { isActive = true }
.onLongPressGesture { print("long press") }
}
}
}
}Dynamic NavigationLinks
When the number of links is not known at compile time, store the activation flags in an array and bind each link to the corresponding element:
struct ContentView: View {
@State private var items: [Int] = []
@State private var isActives: [Bool] = []
var body: some View {
NavigationView {
ScrollView {
ForEach(items, id: \ .self) { item in
NavigationLink(
destination: Text("Destination View \(item)"),
isActive: $isActives[items.firstIndex(of: item)!]
) {
Text("Navigate View \(item)")
.onTapGesture { isActives[items.firstIndex(of: item)!] = true }
.onLongPressGesture { print("long press \(item)") }
}
}
}
}
.onAppear {
items = [1, 2]
isActives = Array(repeating: false, count: items.count)
}
}
}Conclusion
The article covered the fundamental and advanced usage of NavigationView and NavigationLink in SwiftUI, including title bar handling, custom button styles, gesture combinations, the isActive parameter, and dynamic link generation, providing a solid foundation for building complex navigation flows in iOS applications.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Sohu Tech Products
A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
