NavigationStack este un container de navigație modern în SwiftUI, introdus în iOS 16+ care a înlocuit NavigationView. Conform Apple Developer Documentation, 2024, NavigationStack gestionează stiva de ecrane printr-o cale de navigație sigură din punctul de vedere al tipurilor (NavigationPath), suportă navigația profundă, revenirea programatică la ecranul principal și păstrarea stării la modificarea datelor. Spre deosebire de NavigationView, NavigationStack nu necesită împlierea în containere suplimentare și oferă un Binding direct la calea de navigație.
Principalele
NavigationStack este un View container care implementează navigația pe bază de stivă (LIFO). Gestionează istoricul tranzițiilor, permițând plasarea de noi ecrane pe stivă și revenirea prin butonul de sistem «Înapoi» sau programatic. NavigationStack face parte din SwiftUI începând cu iOS 16, iPadOS 16, macOS 13, watchOS 9 și tvOS 16.
Principala inovație a NavigationStack este calea de navigație sigură tipologic. În loc să indicați direct destination la crearea NavigationLink, plasați o valoare (value) în cale, iar înregistrarea View-ării țintă are loc separat prin modificatorul .navigationDestination(for:destination:). Aceasta separă navigația de afișare, făcând codul mai modular și mai testabil.
Conform WWDC 2022 (Session 10054), NavigationStack utilizează un nou mecanism de navigație bazat pe ObservableObject și ciclul de viață SwiftUI. Spre deosebire de NavigationView care se baza pe UINavigationController sub capotă, NavigationStack este implementat întreg în SwiftUI, ceea ce îmbunătățește predictibilitatea și compatibilitatea cu ciclul de viață SwiftUI.
NavigationStack primește un View rădăcină și o cale de navigație opțională (Binding la NavigationPath sau un array de valori Hashable). Toate ecranele copil sunt plasate în stivă prin NavigationLink sau prin adăugarea programatică de valori la cale.
NavigationView a fost principalul container de navigație SwiftUI până la iOS 16. Gestiona automat UINavigationController sub capotă, ceea ce ducea la o serie de probleme: comportament imprevizibil la modificarea datelor, dificultăți cu navigația programatică și lipsa siguranței tipologice.
| Caracteristică | NavigationStack (iOS 16+) | NavigationView (iOS 13–15) |
|---|---|---|
| Tip navigație | Stivă (LIFO) | Stivă (LIFO) |
| Cale navigație | Tipizată (NavigationPath) | Neacceptată |
| Deep linking | Suport încorporat | Necesită hack-uri |
| Revenire programatică | Prin cale (pop, popToRoot) | dismiss, presentationMode |
| Sub capotă | SwiftUI native | UINavigationController |
| Compatibilitate | iOS 16+ | iOS 13+ |
Avantajul cheie NavigationStack — navigație sigură tipologic. Definiți calea ca un array de tipuri concrete (sau NavigationPath pentru stive eterogene) și înregistrați destination pentru fiecare tip. Aceasta elimină erorile de nepotrivire a tipurilor și face navigația predictibilă.
NavigationView este învechit în iOS 17. Apple recomandă migrarea la NavigationStack pentru toate proiectele noi și la actualizarea versiunii minime la iOS 16.
NavigationPath este un tip care reprezintă calea de navigație în NavigationStack. Poate stoca valori eterogene (AnyHashable) sau poate fi utilizat cu un tip concret prin Binding la un array [T: Hashable]. NavigationPath se codifică și se decodifică automat pentru păstrarea stării.
struct ContentView: View {
@State private var path = NavigationPath()
var body: some View {
NavigationStack(path: $path) {
HomeView()
.navigationDestination(for: String.self) { value in
DetailView(id: value)
}
.navigationDestination(for: Int.self) { value in
NumberView(number: value)
}
}
}
func goToRoot() {
path.removeLast(path.count)
}
func pushDeepLink() {
path.append("detail_42")
}
}
Stivă eterogenă: NavigationPath poate conține valori de tipuri diferite, dacă implementează Hashable. De exemplu, primul ecran poate accepta String (ID), al doilea — Int (număr), al treilea — un enum personalizat Route. Pentru afișarea fiecărui tip se înregistrează un .navigationDestination separat.
Suport Codable: NavigationPath implementează Codable dacă toate valorile din cale sunt de asemenea Codable + Hashable. Aceasta permite salvarea și restaurarea stării de navigație la repornirea aplicației sau la trecerea în fundal.
.navigationDestination(for:destination:) — un modificator care înregistrează View-ul \u021bintă pentru un tip specific de date. Când NavigationLink plasează o valoare de acest tip în cale, SwiftUI găsește automat .navigationDestination corespunzător și creează ecranul.
enum AppRoute: Hashable {
case profile(UserID)
case settings
case about
}
struct AppNavigation: View {
@State private var path = NavigationPath()
var body: some View {
NavigationStack(path: $path) {
HomeView()
.navigationDestination(for: AppRoute.self) { route in
switch route {
case .profile(let id):
ProfileView(userId: id)
case .settings:
SettingsView()
case .about:
AboutView()
}
}
}
}
}
// Navigate: path.append(AppRoute.profile("user_123"))
Regulă importantă: .navigationDestination trebuie aplicat unui View care se află în interiorul NavigationStack și înainte ca NavigationLink să plaseze o valoare în cale. De obicei se adaugă la View-ul rădăcină sau la containerul secțiunii. Dacă .navigationDestination nu este găsit pentru tipul valorii, tranziția nu are loc.
Conform SwiftUI Engineering (2023), .navigationDestination poate fi înregistrat la diferite niveluri ale ierarhiei. SwiftUI caută cel mai apropiat destination potrivit la încercarea de navigație. Aceasta permite suprascrierea destination pentru un tip în diferite părți ale aplicației.
Pattern 1: navigație prin enum Route. Definiți un enum cu valori asociate pentru toate ecranele aplicației. Utilizați un .navigationDestination pentru AppRoute și switch pentru rutare. Aceasta asigură o singură sursă de adevăr pentru toate tranzițiile posibile din aplicație.
struct StoreView: View {
@State private var path: [ProductRoute] = []
var body: some View {
NavigationStack(path: $path) {
ProductGrid()
.navigationDestination(for: ProductRoute.self) { route in
switch route {
case .detail(let product):
ProductDetail(product: product)
case .reviews(let productId):
ReviewsView(productId: productId)
}
}
}
}
}
enum ProductRoute: Hashable {
case detail(Product)
case reviews(String)
}
Pattern 2: navigație programatică și deep linking. NavigationStack permite gestionarea programatică a stivei: adăugarea, eliminarea ecranelor și revenirea la rădăcină. Acest lucru este necesar pentru notificări push, linkuri profunde și restaurarea navigației după repornire.
Pattern 3: array de tipuri în loc de NavigationPath. Dacă toate ecranele utilizează un singur tip (de exemplu, String sau un enum personalizat), utilizați Binding la [T]. Aceasta oferă o tipizare mai strictă și o performanță mai bună decât NavigationPath. NavigationPath este justificat pentru stive eterogene cu diferite tipuri de ecrane.
Conform Point-Free (2024), NavigationStack cu enum Route este modalitatea preferată de organizare a navigației în aplicațiile SwiftUI. Face toate tranzițiile posibile explicite, sigure tipologic și testabile, ceea ce este deosebit de important pentru proiecte mari cu zeci de ecrane.
Întrebări frecvente
NavigationStack — un container de navigație SwiftUI (iOS 16+) care gestionează stiva de ecrane printr-o cale sigură tipologic. A înlocuit NavigationView, oferind suport pentru deep linking, navigație programatică și salvare a stării.
NavigationStack utilizează o cale sigură tipologic (NavigationPath) în loc de legarea directă a NavigationLink cu destination. Suportă navigația programatică, deep linking și Codable pentru salvarea stării. Funcționează pe SwiftUI, nu prin UINavigationController.
NavigationPath este un tip care reprezintă secvența ecranelor în stivă. Adăugați valori în cale prin path.append() sau prin NavigationLink cu value. Pentru afișarea fiecărui tip se înregistrează .navigationDestination. NavigationPath suportă Codable și salvarea automată a stării.
Prin gestionarea programatică a căii: după procesarea URL-ului, apelați path.append() cu valoarea corespunzătoare a rutei. NavigationStack va afișa automat ecranul țintă. Revenirea la rădăcină — path.removeLast(path.count).
Da, dacă versiunea minimă este iOS 16+. NavigationView este învechit în iOS 17. Migrarea oferă navigație sigură tipologic, suport pentru deep linking și o mai bună conformitate cu ciclul de viață SwiftUI. Pentru proiecte cu iOS 15 și mai jos, încă utilizați NavigationView.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și