NavigationLink — це елемент керування в SwiftUI, призначений для переходу на інший екран у NavigationStack або NavigationView. Згідно з Apple Developer Documentation, 2024, NavigationLink створює кнопку, при натисканні на яку цільовий View поміщається в навігаційний стек. В iOS 16+ рекомендується використовувати NavigationLink з value та NavigationDestination, а не з destination безпосередньо, щоб уникнути передчасної ініціалізації цільових View.
Головне
NavigationLink — це View, яке при натисканні ініціює навігаційний перехід. Усередині NavigationStack натискання на NavigationLink поміщає цільовий екран у стек і відображає системну кнопку «Назад». NavigationLink існує з iOS 13 і є основним способом користувацької навігації в SwiftUI.
NavigationLink не успадковується від UIButton — це SwiftUI View, яке автоматично адаптується до контексту. Усередині List NavigationLink відображається зі стрілкою розкриття (disclosure indicator). Поза списком NavigationLink поводиться як звичайна кнопка, але з навігаційною поведінкою.
За даними SwiftUI Lab (2024), NavigationLink є одним із найбільш використовуваних View у SwiftUI-додатках, поступаючись лише Text, Image та VStack. Розуміння відмінностей між формами ініціалізації критично важливе для продуктивності та передбачуваної поведінки навігації.
При натисканні NavigationLink додає значення (або destination) у навігаційний стек, пов'язаний із найближчим NavigationStack або NavigationView. SwiftUI використовує EnvironmentValue для передачі шляху навігації через ієрархію View. NavigationLink читає цей шлях з Environment і при натисканні модифікує його.
NavigationLink має дві основні форми: з destination (пряме зазначення цільового View) та з value (значення для NavigationDestination). Вибір форми залежить від версії iOS та архітектури навігації.
| Форма | Ініціалізатор | iOS 13–15 | iOS 16+ |
|---|---|---|---|
| Destination | NavigationLink(destination:label:) | Рекомендується | Не рекомендується |
| Value | NavigationLink(value:label:) | Недоступна | Рекомендується |
| IsActive | NavigationLink(isActive:destination:label:) | Програмна навігація | Не рекомендується |
Destination-форма (iOS 13+): NavigationLink(destination: DetailView(), label: { Text("Open") }). Ця форма створює DetailView одразу під час рендерингу NavigationLink, навіть якщо користувач не натиснув на посилання. Це призводить до передчасної ініціалізації View та потенційних проблем із продуктивністю, якщо destination View виконує важкі операції в ініціалізаторі.
Value-форма (iOS 16+): NavigationLink(value: "detail_42", label: { Text("Open") }). Цільовий View створюється лише при натисканні на посилання, коли SwiftUI знаходить відповідний .navigationDestination. Це запобігає передчасній ініціалізації та робить навігацію більш передбачуваною.
NavigationLink з NavigationStack в iOS 16+ вимагає переходу на value-форму. Ви визначаєте тип даних для навігації (String, Int, enum Route) та реєструєте destination через .navigationDestination. NavigationLink поміщає в стек лише значення, а SwiftUI створює цільовий View при натисканні.
struct CatalogView: View {
let categories: [String]
var body: some View {
List(categories, id: \.self) { category in
NavigationLink(value: category) {
Text(category)
}
}
.navigationDestination(for: String.self) { category in
CategoryView(name: category)
}
}
}
// Programmatic navigation:
struct DeepLinkView: View {
@State private var path: [AppRoute] = []
var body: some View {
NavigationStack(path: $path) {
HomeView()
.navigationDestination(for: AppRoute.self) { route in
switch route {
case .detail(let id): DetailView(id: id)
case .settings: SettingsView()
}
}
.toolbar {
Button("Open Settings") {
path.append(AppRoute.settings)
}
}
}
}
}
Програмний перехід: додавання значення в path (через path.append) еквівалентно натисканню NavigationLink з таким самим значенням. Це дозволяє реалізувати навігацію з ViewModel, Coordinator або у відповідь на push-сповіщення.
IsActive форма (NavigationLink(isActive:destination:label:)) доступна для сумісності, але не рекомендується в iOS 16+. Використовуйте value-форму з Binding до масиву шляху або NavigationPath.
NavigationLink у List автоматично відображає стрілку розкриття (chevron) у правій частині рядка, сигналізуючи користувачеві, що натискання приведе до переходу на інший екран. List керує відображенням стрілки автоматично — на відміну від звичайного NavigationLink поза списком, де стрілки немає.
З iOS 16 List з NavigationLink автоматично використовує value-форму всередині List(data:rowContent:). При використанні ForEach всередині List стрілка розкриття також додається автоматично. Цю поведінку не можна вимкнути через модифікатори — лише заміна NavigationLink на Button може прибрати стрілку.
Проблема з destination-формою в List: якщо ви використовуєте NavigationLink(destination:label:) всередині List, усі destination View створюються одразу під час завантаження списку, незалежно від того, натиснув користувач на посилання чи ні. Для списків із великою кількістю рядків це може суттєво сповільнити початкове завантаження та збільшити споживання пам'яті. Value-форма з NavigationStack вирішує цю проблему.
За даними WWDC 2022 (Session 10054), Apple рекомендує використовувати NavigationStack та value-форму NavigationLink для нових проєктів. Це особливо важливо для List з динамічними даними, де кількість рядків може бути великою.
Паттерн 1: кастомний вигляд NavigationLink. NavigationLink приймає будь-яке View як label, дозволяючи створювати довільний дизайн для посилання. Усередині List це особливо зручно — ви отримуєте стрілку розкриття автоматично при використанні NavigationLink.
NavigationLink(value: ProductRoute.detail(product)) {
HStack {
AsyncImage(url: product.imageURL)
.frame(width: 60, height: 60)
VStack(alignment: .leading) {
Text(product.name).font(.headline)
Text(product.price) .foregroundColor(.secondary)
}
}
.padding(8)
}
Паттерн 2: NavigationLink без стрілки (кастомна кнопка). Якщо вам не потрібна стрілка розкриття, використовуйте Button для програмної навігації: path.append(value). Це корисно для кастомних елементів інтерфейсу, де NavigationLink виглядає неприродно.
Паттерн 3: умовна навігація. Ви можете заблокувати NavigationLink, використовуючи порожнє destination або не додаючи .navigationDestination для певних значень. Програмна навігація через path дозволяє перевіряти умови перед додаванням значення.
За даними Hacking with Swift (2024), більшість проблем із NavigationLink пов'язана з використанням destination-форми в старих проєктах. При міграції на NavigationStack замініть усі NavigationLink(destination:label:) на NavigationLink(value:label:) та додайте .navigationDestination на кореневому рівні.
Часті запитання
NavigationLink — це View для переходу на інший екран у SwiftUI. При натисканні поміщає цільовий екран у навігаційний стек NavigationStack або NavigationView. Підтримує дві форми: з destination (цільовим View) та з value (значенням для маршрутизації).
Value-форма (iOS 16+) краща: цільовий View створюється лише при натисканні, а не при рендерингу посилання. Destination-форма створює View одразу, що може викликати проблеми з продуктивністю. Для проєктів з iOS 16+ використовуйте value + NavigationDestination.
SwiftUI автоматично додає disclosure indicator (стрілку) до NavigationLink всередині List, сигналізуючи про можливість переходу. Цю поведінку не можна вимкнути. Якщо стрілка не потрібна, використовуйте Button з програмною навігацією через path.append().
Використовуйте NavigationStack з Binding шляхом і додавайте значення через path.append(value). Це еквівалентно натисканню NavigationLink з таким самим value. Програмна навігація дозволяє реалізувати DeepLink-и, push-сповіщення та Coordinator-паттерн.
Destination-форма може впливати, якщо цільові View виконують важкі операції в ініціалізаторі — всі destination створюються під час рендерингу списку. Value-форма з NavigationStack вирішує цю проблему, створюючи View лише при натисканні. Для списків із 50+ рядками різниця суттєва.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.