Попрощайтесь с SwiftUI NavigationView с iOS 16

SwiftUI NavigationView с самого начала был ахиллесовой пятой фреймворка. Начиная с изначального запрета ленивых загрузок целевых представлений внутри NavigationLink (хотя это было решено позже) и заканчивая неспособностью программно перемещаться по глубоким ссылкам, структура навигации SwiftUI часто вынуждала нас возвращаться к использованию UINavigationController.

К нашей передышке, в iOS 16 Apple предложила новую навигационную архитектуру, управляемую данными, вместо прежней структуры, управляемой представлениями.

Основные новые изменения API навигации включают в себя новый NavigationStack, который позволяет отправлять и извлекать представления из стека, NavigationPath для управления стеком маршрутизации и модификатор navigationDestination для эффективной программной навигации по представлениям. С тем же обновлением они устарели NavigationView.

Привет, NavigationStack

Интеграция NavigationStack в наш стек иерархии представлений очень проста:

NavigationStack {
       NavigationLink {
            Text("Destination Screen")
       } label: {
            Text("Goto Next Screen")
       }
}

В некоторых тривиальных случаях мы можем напрямую провести рефакторинг нашего старого контейнера NavigationView с новым контейнером NavigationStack. Однако обратите внимание на новый синтаксис инициализации NavigationLink.

API теперь содержит синтаксис value-label с меткой, содержащей представление контента для ссылки, и значением, содержащим построитель целевого представления.

Также стоит отметить, что старые методы инициализации NavigationLink, такие как NavigationLink(isActive:destination:label:), устарели.

Точно так же NavigationLink(destination:tag:selection:) также устарел в iOS 16, что означает, что рефакторинг программной навигации на основе NavigationLink потребует совершенно другого кода.

Программная навигация с использованием модификатора 'navigationDestination"

В предыдущем разделе мы увидели, как установить целевое представление NavigationLink в самом коде инициализации. Однако вы, возможно, помните ту боль, которую доставляли нам isActive логические флаги при создании сложных навигационных структур до iOS 16.

К счастью, начиная с iOS 16 мы можем установить целевой вид внутри модификатора .navigationDestination. navigationDestination дает нам возможность программно направлять на разные экраны в зависимости от типа. Вы также можете добавить несколько модификаторов navigationDestination для разных типов представления.

В приведенном ниже примере мы создали навигационное приложение SwiftUI, которое создает такое же представление списка на экране назначения:

Маршрутизация NavigationLink с использованием NavigationPath

Раньше для маршрутизации NavigationLink у нас было tags.

В iOS 16 у нас появился новый мощный NavigationPath, который может хранить стертые данные типа, относящиеся к представлениям, отображаемым в NavigationStack.

Сила NavigationPath заключается в его способности легко выталкивать из стека представления, принадлежащие разным типам данных.

Рассмотрим приведенное ниже приложение, в котором мы подключили NavigationPath к нашему NavigationStack:

Мы установили наш NavigationPath внутри класса ObservableObject и установили его в EnvironmentObject, чтобы передать его дочерним представлениям. Хотя вы также можете использовать @Binding для того же.

Обратите внимание на измененный файл NavigationStack(path:) init.

Вот код для RowListsView:

Мы немного изменили приведенное выше представление SwiftUI — чтобы включить настраиваемые кнопки «Назад», которые программно изменят NavigationPath, что, в свою очередь, изменит представление NavigationStack:

Мы увидели, как легко вернуться к корню, вызвав следующий фрагмент кода:

router.path = .init()

Вы можете вернуться к любому экрану, нажав и удерживая кнопку «Назад», которая показывает раскрывающийся список с предыдущими заголовками экрана. Теперь заголовки будут отображать back по умолчанию, но вы можете настроить их, установив модификатор .navigationTitle(string:).

На этом вводная статья о новом навигационном стеке SwiftUI завершена, но вы можете сделать гораздо больше, используя новые шаблоны, например, обрабатывать глубокие ссылки и многое другое.

Кроме того, для поддержки новых API-интерфейсов навигации в предыдущих версиях iOS есть потрясающая библиотека с открытым исходным кодом.

Это все на данный момент. Вот суть всего фрагмента кода SwiftUI.