Mobile Development 16 min read

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.

Sohu Tech Products
Sohu Tech Products
Sohu Tech Products
Using NavigationView and NavigationLink in SwiftUI: Basics, Customizations, and Advanced Techniques

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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Mobile DevelopmentiOSSwiftSwiftUINavigationLinkNavigationViewUI Navigation
Sohu Tech Products
Written by

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.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.