tgoop.com/mobileproglib/6301
Last Update:
NavigationPath
NavigationStack
и NavigationPath
в SwiftUI предоставляют мощный и гибкий способ выполнять программную навигацию в приложении. Когда вы управляете навигацией, часто возникает необходимость программно открывать (push) и закрывать (pop) экраны. NavigationPath
позволяет делать это, сохраняя типобезопасность и гибкость.
🔹 NavigationStack(root:)
Инициализатор по умолчанию задаёт корень навигационной иерархии и управляет путём навигации “за кулисами”. Если вы хотите получить больший контроль и управлять навигацией программно, можно хранить путь в переменной @State
и передавать его в инициализатор NavigationStack(path:root:)
.
Параметр path должен быть Binding<Data>
, и есть два способа его использования.
Первый способ — использовать массив определённого типа, который реализует протокол Hashable
. Это удобно, если весь стек навигации основан на одном типе данных.
@State private var path: [Color] = []
NavigationStack(path: $path) {
List {
ForEach(colors, id: \.self) { color in
Button {
path.append(color)
} label: {
...
}
}
}
.navigationDestination(for: Color.self) { color in
VStack {
color
...
Button("Pop to root") {
path.removeAll()
}
}
...
}
}
В примере выше навигационный стек поддерживается массивом объектов
Color
, который выступает в роли NavigationPath
. Каждый раз, когда элемент добавляется в path, модификатор navigationDestination(for:)
показывает соответствующий экран. Вызов path.removeAll()
очищает стек и возвращает пользователя к корневому экрану.Этот подход идеально подходит для чистой, типобезопасной навигации с минимальной настройкой, особенно если вы работаете с одним типом данных.
Когда вы находитесь в корневом экране, массив пуст.
При переходе вперёд — он заполняется элементами, где последний элемент массива соответствует текущему экрану.
Чтобы открыть новый экран — добавляем элемент, чтобы вернуться назад — удаляем последний.
NavigationPath
для нескольких типовЕсли навигационный стек может содержать разные типы данных (например,
Color
, String
или пользовательские типы), лучше использовать NavigationPath
. Он работает как type-erased список данных, но при этом сохраняет достаточно информации, чтобы SwiftUI знал, какой экран показать для каждого типа.@State private var path = NavigationPath()
NavigationStack(path: $path) {
List {
Section("Colors") {
ForEach(colors, id: \.self) { color in
Button {
path.append(color)
} label: {
...
}
}
}
Section("Genres") {
ForEach(genres, id: \.self) { genre in
Button {
path.append(genre)
} label: {
...
}
}
}
}
.navigationDestination(for: Color.self) { color in
VStack {
...
Button("Pop to root") {
path.removeLast(path.count)
}
}
...
}
.navigationDestination(for: String.self) { genre in
VStack {
...
Button("Pop to root") {
path.removeLast(path.count)
}
}
...
}
}
С
NavigationPath
вы можете добавлять разные типы данных в стек. Для каждого типа нужно задать отдельный navigationDestination(for:destination:)
, чтобы описать, как отображать соответствующий экран.Если вы добавите значение в
NavigationPath
, но не определите navigationDestination
для его типа,ошибки компиляции не будет — однако пользователь увидит пустой экран с предупреждением.
Такой подход более гибкий, особенно для приложений, навигация в которых зависит от различных моделей данных.
#PixelPerfect #MiddlePath #SwiftUI