Навигация описывает, как пользователи перемещаются по приложению. Пользователи взаимодействуют с элементами пользовательского интерфейса, обычно нажимая или щелкая по ним, а приложение реагирует, отображая новый контент. Если пользователь хочет вернуться к предыдущему контенту, он использует жест «Назад» или нажимает кнопку «Назад».
Моделирование состояния навигации
Удобный способ моделирования такого поведения — использовать стек контента. Когда пользователь переходит к новому контенту, он помещается наверх стека. При возвращении к предыдущему контенту он удаляется из стека, и отображается предыдущий контент. В терминах навигации этот стек обычно называется стеком возврата, поскольку он представляет собой контент, к которому пользователь может вернуться .

Создайте обратную стопку
В Navigation 3 стек переходов назад фактически не содержит контента. Вместо этого он содержит ссылки на контент , называемые ключами . Ключи могут быть любого типа, но обычно представляют собой простые сериализуемые классы данных. Использование ссылок вместо контента имеет следующие преимущества:
- Навигация по нему осуществляется простым нажатием клавиш на задней панели.
- Если ключи сериализуемы, стек переходов назад можно сохранить в постоянном хранилище, что позволит ему пережить изменения конфигурации и завершение процесса. Это важно, поскольку пользователи ожидают, что они выйдут из вашего приложения, вернутся к нему позже и продолжат работу с того места, где остановились, с тем же отображаемым контентом. Подробнее см. в разделе «Сохранение стека переходов назад» .
Ключевая концепция API Navigation 3 заключается в том, что вы являетесь владельцем стека переходов. Библиотека:
- Ожидается, что ваш стек переходов будет представлять собой
List<T>
, поддерживаемый снимком состояния, гдеT
— типkeys
вашего стека переходов. Вы можете использоватьAny
или предоставить собственные, более строго типизированные ключи. Термины «push» и «pop» означают, что они добавляют или удаляют элементы из конца списка. - Наблюдает за стеком переходов и отображает его состояние в пользовательском интерфейсе с помощью
NavDisplay
.
В следующем примере показано, как создавать ключи и стек переходов, а также изменять стек переходов в ответ на события навигации пользователя:
// Define keys that will identify content data object ProductList data class ProductDetail(val id: String) @Composable fun MyApp() { // Create a back stack, specifying the key the app should start with val backStack = remember { mutableStateListOf<Any>(ProductList) } // Supply your back stack to a NavDisplay so it can reflect changes in the UI // ...more on this below... // Push a key onto the back stack (navigate forward), the navigation library will reflect the change in state backStack.add(ProductDetail(id = "ABC")) // Pop a key off the back stack (navigate back), the navigation library will reflect the change in state backStack.removeLastOrNull() }
Ключи к содержанию
Контент моделируется в Navigation 3 с помощью класса NavEntry
, содержащего компонуемую функцию. Он представляет собой конечный пункт — отдельный фрагмент контента, к которому пользователь может перемещаться вперёд и назад .
Элемент NavEntry
также может содержать метаданные — информацию о содержимом. Эти метаданные могут считываться объектами-контейнерами, такими как NavDisplay
, чтобы помочь им определить, как отображать содержимое элемента NavEntry
. Например, метаданные можно использовать для переопределения анимации по умолчанию для конкретного NavEntry
. metadata
NavEntry представляют собой сопоставление String
ключей с Any
значениями, обеспечивая универсальное хранилище данных.
Чтобы преобразовать key
в NavEntry
, создайте Entry Provider. Это функция, которая принимает key
и возвращает NavEntry
для этого key
. Обычно он определяется как лямбда-параметр при создании NavDisplay
.
Существует два способа создания поставщика данных: либо путем непосредственного создания лямбда-функции, либо с использованием entryProvider
DSL.
Создайте функцию Entry Provider напрямую
Обычно функция поставщика записей создается с помощью оператора when
с ветвью для каждого из ваших ключей.
entryProvider = { key -> when (key) { is ProductList -> NavEntry(key) { Text("Product List") } is ProductDetail -> NavEntry( key, metadata = mapOf("extraDataKey" to "extraDataValue") ) { Text("Product ${key.id} ") } else -> { NavEntry(Unit) { Text(text = "Invalid Key: $it") } } } }
Используйте entryProvider
DSL
DSL entryProvider
может упростить вашу лямбда-функцию, избавляя от необходимости проверять каждый тип ключа и создавать NavEntry
для каждого из них. Используйте для этого функцию-конструктор entryProvider
. Она также включает резервное поведение по умолчанию (выдачу ошибки), если ключ не найден.
entryProvider = entryProvider { entry<ProductList> { Text("Product List") } entry<ProductDetail>( metadata = mapOf("extraDataKey" to "extraDataValue") ) { key -> Text("Product ${key.id} ") } }
Обратите внимание на следующее в этом фрагменте:
-
entry
используется для определенияNavEntry
с заданным типом и компонуемым содержимым -
entry
принимает параметрmetadata
для установкиNavEntry.metadata
Отобразить стек назад
Стек переходов представляет собой состояние навигации вашего приложения. При каждом изменении стека переходов пользовательский интерфейс приложения должен отражать новое состояние. В Navigation 3 элемент NavDisplay
отслеживает стек переходов и соответствующим образом обновляет свой пользовательский интерфейс. Создайте его со следующими параметрами:
- Ваш стек переходов должен иметь тип
SnapshotStateList<T>
, гдеT
— тип ключей вашего стека переходов. Это наблюдаемыйList
, который запускает перекомпоновкуNavDisplay
при его изменении. -
entryProvider
для преобразования ключей в стеке переходов в объектыNavEntry
. - При желании можно указать лямбда-выражение в параметре
onBack
. Оно вызывается, когда пользователь инициирует событие возврата.
В следующем примере показано, как создать NavDisplay
.
data object Home data class Product(val id: String) @Composable fun NavExample() { val backStack = remember { mutableStateListOf<Any>(Home) } NavDisplay( backStack = backStack, onBack = { backStack.removeLastOrNull() }, entryProvider = { key -> when (key) { is Home -> NavEntry(key) { ContentGreen("Welcome to Nav3") { Button(onClick = { backStack.add(Product("123")) }) { Text("Click to navigate") } } } is Product -> NavEntry(key) { ContentBlue("Product ${key.id} ") } else -> NavEntry(Unit) { Text("Unknown route") } } } ) }
По умолчанию NavDisplay
отображает самый верхний элемент NavEntry
в стеке на задней панели в однопанельном макете. Следующая запись демонстрирует работу этого приложения:

NavDisplay
по умолчанию с двумя пунктами назначения.Собираем все вместе
На следующей диаграмме показано, как данные передаются между различными объектами в Navigation 3:

События навигации инициируют изменения . Ключи добавляются или удаляются из стека переходов в ответ на действия пользователя.
Изменение состояния стека переходов запускает извлечение контента .
NavDisplay
(компонуемый элемент, отображающий стек переходов) отслеживает стек переходов. В конфигурации по умолчанию он отображает самую верхнюю запись стека переходов в однопанельном макете. При изменении верхнего ключа в стеке переходовNavDisplay
использует этот ключ для запроса соответствующего контента у поставщика записи.Поставщик записи предоставляет контент . Поставщик записи — это функция, которая преобразует ключ в
NavEntry
. Получив ключ отNavDisplay
, поставщик записи предоставляет связанныйNavEntry
, содержащий как ключ, так и контент.Содержимое отображается .
NavDisplay
получаетNavEntry
и отображает содержимое.