SwiftUI Navigation mit NavigationStack – der komplette Guide
Warum NavigationView nicht mehr reicht
Wenn du mit SwiftUI anfängst, stolperst du schnell über Navigation. Bis iOS 16 war NavigationView der Standard — aber es hatte Probleme: kein programmatisches Navigieren, kein Deep Linking, und auf dem iPad verhielt es sich unvorhersehbar.
NavigationStack löst all das. Es ist seit iOS 16 verfügbar und sollte in jedem neuen Projekt verwendet werden. NavigationView ist deprecated — gewöhn dich gar nicht erst daran.
Die Grundlagen: NavigationStack und NavigationLink
Die einfachste Navigation sieht so aus:
struct ContentView: View {
var body: some View {
NavigationStack {
List {
NavigationLink("Profil", value: "profil")
NavigationLink("Einstellungen", value: "settings")
}
.navigationTitle("Menü")
.navigationDestination(for: String.self) { value in
DetailView(name: value)
}
}
}
}
struct DetailView: View {
let name: String
var body: some View {
Text("Seite: \(name)")
.navigationTitle(name)
}
}
Wichtig: NavigationLink mit value: funktioniert nur zusammen mit .navigationDestination(for:). Das ist Absicht — es trennt das „Wohin" vom „Was wird angezeigt".
Programmatische Navigation mit NavigationPath
Der große Vorteil von NavigationStack gegenüber NavigationView: Du kannst den Navigation-Stack als State verwalten und programmatisch Screens pushen oder poppen.
struct ContentView: View {
@State private var path = NavigationPath()
var body: some View {
NavigationStack(path: $path) {
VStack(spacing: 20) {
Button("Direkt zu Detail") {
path.append("detail-screen")
}
Button("Zurück zum Start") {
path.removeLast(path.count)
}
}
.navigationTitle("Start")
.navigationDestination(for: String.self) { value in
Text(value)
}
}
}
}
NavigationPath ist ein typen-löschender Container. Du kannst verschiedene Typen hineinwerfen — Strings, Integers, eigene Modelle — solange sie Hashable sind.
Mehrere Typen in einem Stack
In der Praxis navigierst du nicht nur zu Strings. So unterstützt du mehrere Typen:
struct ContentView: View {
@State private var path = NavigationPath()
var body: some View {
NavigationStack(path: $path) {
List {
NavigationLink("Artikel", value: Article(title: "SwiftUI"))
NavigationLink("Kategorie", value: Category(name: "iOS"))
}
.navigationDestination(for: Article.self) { article in
ArticleDetailView(article: article)
}
.navigationDestination(for: Category.self) { category in
CategoryView(category: category)
}
}
}
}
Jeder Typ bekommt sein eigenes .navigationDestination. SwiftUI wählt automatisch das richtige.
Deep Linking
Mit programmatischer Navigation ist Deep Linking trivial. Wenn deine App eine URL wie myapp://article/swift-basics empfängt, musst du nur den passenden Wert auf den Stack pushen:
.onOpenURL { url in
if let slug = url.pathComponents.last {
path.append(slug)
}
}
Das funktioniert auch für Push-Notifications, Spotlight-Ergebnisse und Widgets — alles, was einen bestimmten Screen öffnen soll.
iPad: NavigationSplitView
Auf dem iPad willst du keine Push-Navigation, sondern ein Sidebar-Layout. Dafür gibt es NavigationSplitView:
struct iPadView: View {
@State private var selection: String?
var body: some View {
NavigationSplitView {
List(selection: $selection) {
Label("Newsroom", systemImage: "newspaper")
.tag("newsroom")
Label("Einstellungen", systemImage: "gear")
.tag("settings")
}
.navigationTitle("Menü")
} detail: {
switch selection {
case "newsroom":
Text("Newsroom")
case "settings":
Text("Einstellungen")
default:
Text("Wähle einen Bereich")
}
}
}
}
Tipp: Prüfe mit @Environment(\.horizontalSizeClass), ob du auf iPhone oder iPad bist, und zeige die passende Navigation:
@Environment(\.horizontalSizeClass) private var sizeClass
var body: some View {
if sizeClass == .regular {
iPadLayout
} else {
iPhoneLayout
}
}
Häufige Fehler
| Fehler | Lösung |
|---|---|
| <code>NavigationView</code> verwenden | Immer <code>NavigationStack</code> oder <code>NavigationSplitView</code> |
| <code>NavigationLink(destination:)</code> statt <code>value:</code> | <code>value:</code> + <code>.navigationDestination</code> ist die moderne API |
| Verschachtelte <code>NavigationStack</code> | Nur <strong>einen</strong> <code>NavigationStack</code> pro Hierarchie — nicht in jeder Subview einen neuen |
| <code>.navigationTitle</code> außerhalb des Stacks | Der Modifier gehört auf die <strong>innere</strong> View, nicht auf <code>NavigationStack</code> selbst |
| Eigene Back-Buttons | Lass den System-Back-Button. Nutzer erwarten ihn, und er funktioniert mit Swipe-Back |
Fazit
NavigationStack ist die Grundlage jeder modernen SwiftUI-App. Die Trennung von Navigation-State und View-Darstellung macht Deep Linking, programmatische Navigation und Testbarkeit deutlich einfacher als mit dem alten NavigationView. Fang von Anfang an damit an — ein späterer Umbau ist aufwändig.
Mehr über unsere App-Entwicklung →
Dieser Artikel wurde zuletzt am 20. März 2026 aktualisiert. Getestet mit Xcode 26 / iOS 26 / Swift 6.