June 21

124. Адаптируем NavigationSplitView

В iOS 16 добавили NavigationSplitView, чтобы можно было расположить контент в 2 или 3 колонки. В этой мини-статье расскажу основные моменты по адаптации этой штуки в приложении для iOS, чтобы ничего не сломалось.

Вводные

Возьмем iOS-приложение, в котором навигация построена на NavigationStack, т.е. можно ходить по экранам вперед/назад стандартными способами и с помощью navigationDestination. Кстати, подобное приложение я уже показывал в статье 43.

Задача в том, чтобы сохранить внешний вид и поведение приложения на айфоне при переходе с NavigationStack на NavigationSplitView. в приложении со списками (необязательно List, просто любой вертикальный контент в скролле с кнопками для перехода на следующий экран).

Для краткости буду называть NavigationStack просто NS, а NavigationSplitView - NSV.

Важно помнить, что NSV по умолчанию будет показывать все свои столбцы не только на айпаде, но и в том числе на айфонах pro max и plus в ландшафтном режиме.

Основные компоненты

NSV предлагает нам до трех столбцов: sidebar, content, detail. Вот этот инициализатор для примера:

init(
    @ViewBuilder sidebar: () -> Sidebar,
    @ViewBuilder content: () -> Content,
    @ViewBuilder detail: () -> Detail
)

Официальная документация в этом случае меня не порадовала, вот пример описания этих столбцов (на русском для удобства):

  • sidebar - вьюха для отображения колонки слева
  • content - вьюха для отображения колонки по центру
  • detail - вьюха для отображения зоны с детализацией

Дальше будет мое описание, полученное на личном опыте 😁

Sidebar

Именно эта вьюха отображается по умолчанию на айфоне при использовании NS - с нее можно перейти на следующий экран через push (navigationLink).

То есть при замене NS на NSV в нашем приложении именно в sidebar нужно поместить весь контент корневого экрана навигации, который мы хотим видеть на айфоне при отображении условного списка элементов.

Ширину этой вьюхи на айпаде можно настроить модификатором navigationSplitViewColumnWidth, у которого есть 2 версии: первая для конкретной ширины, вторая для нескольких вариантов.

Content

Эта вьюха вряд ли пригодится большинству приложений: она служит первым уровнем детального контента, который можно увидеть при нажатии на элемент списка в sidebar на айпаде, т.е. подойдет для какой-нибудь подкатегории, например.

На айфоне именно тут будут открываться экраны через navigationLink с главного списка, что будет выглядеть нормально (как всегда) в портретном режиме, а вот если приложение поддерживает ландшафтный режим, то все будет выглядеть совсем не как обычно, а прямо как на айпаде - в три столбца.

Detail

Если явно не указать content (из предыдущего раздела статьи) для NSV, то именно в detail будет отображаться экран, открытый через navigationLink (и на айфоне, и на айпаде) в любом режиме (портретный/ландшафтный).

Другие инициализаторы

У NSV есть несколько других инициализаторов, которые могут пригодиться в отдельных случаях - все их можно найти в документации.

Например, можно настроить columnVisibility, чтобы при повороте экрана (меняется horizontalSizeClass) изменять и видимость колонок:

@Environment(\.horizontalSizeClass) var horizontalSizeClass
@State private var columnVisibility = NavigationSplitViewVisibility.automatic
// и потом где-нибудь в onChange(of: ...)
columnVisibility = horizontalSizeClass == .regular && isEmpty
? .detailOnly
: .automatic

Заключение

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

Настройки есть, но как и в случае с привычной навигацией для айфона - не особо разнообразные. Если ваше приложение поддерживает айпад, структура навигации напоминает то, что показывают в официальной документации, и вы поддерживаете iOS 16+ ... немало условий, да? 😁