Добавить объявление

Навигация в SwiftUI: от основ до продвинутых техник

SwiftUI предлагает несколько подходов к организации навигации и с выходом iOS 16 многое изменилось. Разберем ключевые стратегии, которые помогут вам создавать гибкие и поддерживаемые приложения.

Базовая навигация:


Самый простой способ - NavigationLink:

List(customers) { customer in
NavigationLink {
CustomerDetailScreen(customer: customer)
} label: {
Text(customer.name)
}
}

Минус: инициализация CustomerDetailScreen происходит для каждого элемента списка.

Альтернатива: navigationDestination:

List(customers) { customer in
NavigationLink(customer.name, value: customer)
}
.navigationDestination(for: Customer.self) { customer in
CustomerDetailScreen(customer: customer)
}

Плюс: более эффективно, так как обработка навигации централизована.

Динамическая маршрутизация:


Используйте enum для управления сложными сценариями:

enum Route: Hashable {
case dashboard
case detail(Customer)
}

@State private var routes: [Route] = []

NavigationStack(path: $routes) {
Button("Login") {
routes.append(.dashboard) // Программный переход
}
.navigationDestination(for: Route.self) { route in
switch route {
case .dashboard: DashboardView()
case .detail(let customer): CustomerDetailScreen(customer: customer)
}
}
}

Когда использовать:


  • После асинхронных операций (например авторизации).

  • Для глубоких ссылок (deeplinks).

Глобальная маршрутизация:


Чтобы избежать передачи routes через всю иерархию, вынесите логику в Observable класс:

@Observable
class Router {
var routes: [Route] = []

func navigate(to route: Route) {
routes.append(route)
}
}

// В корневом View:
.environment(Router())

Преимущества:


  • Доступ к навигации из любого места.

  • Чистый код без проброса состояний.

Навигация через Environment Values:


Вдохновляемся React и создаем свой navigate:

struct NavigateAction {
let action: (Route) -> Void

func callAsFunction(_ route: Route) {
action(route)
}
}

// Использование:
@Environment(\.navigate) private var navigate

Button("Войти") {
navigate(.dashboard)
}

Почему это удобно:


  • Интуитивный синтаксис.

  • Подходит для сложных сценариев.

Навигация во вкладках (TabView):


Каждая вкладка должна иметь свой NavigationStack:

enum AppScreen: Hashable {
case patients, doctors
}

TabView {
PatientsScreen()
.tabItem {
Label("Пациенты", systemImage: "heart")
}

DoctorsScreen()
.tabItem {
Label("Врачи", systemImage: "stethoscope")
}
}

Важно:


  • Не используйте общий Router для вкладок.

  • Каждый NavigationStack управляет своим стеком.

Модальные окна и навигация:


Модальные окна - это не часть стека навигации. Для них лучше использовать @State или отдельный сервис:

.sheet(isPresented: $showModal) {
ModalView()
}

Вывод:


  • Для простых приложений - NavigationLink или navigationDestination.

  • Для сложных сценариев - глобальный Router + enum маршруты.

  • Для вкладок - отдельные NavigationStack на каждую вкладку.


Главное: не усложняйте архитектуру раньше времени. Начинайте с простого и масштабируйте по мере роста приложения.
13.08.2025 11 425