Компонент Navigation предоставляет простой и общий способ перехода к пункту назначения. Этот интерфейс поддерживает различные контексты и фреймворки пользовательского интерфейса. Например, вы можете использовать компонент Navigation с Compose, представлениями, фрагментами, действиями и даже пользовательскими фреймворками пользовательского интерфейса.
В этом руководстве описывается, как использовать компонент Navigation для перехода к пункту назначения в различных контекстах.
Использование NavController
Для перемещения между пунктами назначения используется клавиша NavController.
Подробнее о том, как создать экземпляр класса, читайте в разделе Создание контроллера навигации. В этом руководстве рассказывается, как им пользоваться.
Навигация
Независимо от того, какой фреймворк пользовательского интерфейса вы используете, для перехода к пункту назначения можно использовать одну функцию: NavController.navigate().
Для navigate() доступно много перегрузок. Перегрузка, которую вы должны выбрать, соответствует вашему точному контексту. Например, одна перегрузка используется при переходе к composable-функции, а другая – при переходе к представлению.
Ниже описаны некоторые основные перегрузки navigate(), которые вы можете использовать.
Как перейти к composable-функции
Для перехода к composable-функции используйте NavController.navigate<T>.
При такой перегрузке navigate() принимает один аргумент route, для которого вы передаете тип. Он служит ключом к пункту назначения.
@Serializable
object FriendsList
navController.navigate(route = FriendsList)
Чтобы перейти к composable-функции в графе навигации, сначала определите NavGraph так, чтобы каждый пункт назначения соответствовал типу. Для composable-функций это делается с помощью функции composable().
Как передавать события из composable-функций
Когда composable-функции нужно перейти на новый экран, не следует передавать ей ссылку на NavController, чтобы она могла напрямую вызвать navigate().
Согласно принципам однонаправленного потока данных (UDF), composable-функция должна вместо этого предоставлять событие, которое обрабатывает NavController.
Проще говоря, у composable-функции должен быть параметр типа () -> Unit.
Когда вы добавляете пункты назначения в NavHost с помощью функции composable(), передайте вызов NavController.navigate() в composable-функцию.
Пример приведен в следующем подразделе.
Пример
В качестве демонстрации предыдущих разделов обратите внимание на эти моменты в следующем фрагменте:
- Каждый пункт назначения в графе создается с использованием маршрута, который представляет собой сериализуемый объект или класс, описывающий данные, необходимые для этого пункта назначения.
- Composable-функция
MyAppNavHostсодержит экземплярNavController. - Соответственно, вызовы
navigate()должны происходить там, а не в composable-функции более низкого уровня, напримерProfileScreen. ProfileScreenсодержит кнопку, при нажатии на которую пользователь переходит на страницуFriendsList. Однако он не вызываетnavigate().- Вместо этого кнопка вызывает функцию, которая передается в параметре
onNavigateToFriends. - Когда
MyAppNavHostдобавляетProfileScreenв граф навигации, дляonNavigateToFriendsон передает лямбду, которая вызываетnavigate(route = FriendsList). - Это гарантирует, что при нажатии кнопки
ProfileScreenпользователь перейдет кFriendsListScreen.
@Serializable
object Profile
@Serializable
object FriendsList
@Composable
fun MyAppNavHost(
modifier: Modifier = Modifier,
navController: NavHostController = rememberNavController(),
) {
NavHost(
modifier = modifier,
navController = navController,
startDestination = Profile
) {
composable<Profile> {
ProfileScreen(
onNavigateToFriends = { navController.navigate(route = FriendsList) },
/*...*/
)
}
composable<FriendsList> { FriendsListScreen(/*...*/) }
}
}
@Composable
fun ProfileScreen(
onNavigateToFriends: () -> Unit,
/*...*/
) {
/*...*/
Button(onClick = onNavigateToFriends) {
Text(text = "See friends list")
}
}
Переход по целочисленному идентификатору
Чтобы перейти к пункту назначения, используя целочисленный идентификатор, вызовите перегрузку navigate(int). В качестве значения используется идентификатор ресурса действия или целевой страницы. В следующем фрагменте кода показано, как использовать эту перегрузку для перехода к ViewTransactionsFragment:
Kotlin
viewTransactionsButton.setOnClickListener { view ->
view.findNavController().navigate(R.id.viewTransactionsAction)
}
Java
viewTransactionsButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Navigation.findNavController(view).navigate(R.id.viewTransactionsAction);
}
});
При навигации с помощью идентификаторов по возможности используйте действия. Действия предоставляют дополнительную информацию в вашем графе навигации, визуально показывая, как ваши пункты назначения связаны друг с другом.
Как перейти из Compose в приложение на основе фрагментов
Если вы используете Jetpack Compose в архитектуре Navigation на основе Fragment (например, в приложении со смешанными представлениями и Compose), вы не можете использовать типобезопасные маршруты Compose для прямой навигации. Вместо этого используйте целочисленные идентификаторы (действия), определенные в XML-графе навигации.
Чтобы изменить пункты назначения из кода Compose, предоставьте событие (лямбда) из вашей composable-функции:
@Composable
fun MyScreen(onNavigateToProfile: () -> Unit) {
Button(onClick = { onNavigateToProfile() }) {
Text("Go to Profile")
}
}
В своем фрагменте свяжите Compose и компонент Navigation на основе фрагментов, вызвав NavController фрагмента при запуске события:
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return ComposeView(requireContext()).apply {
setContent {
MyScreen(onNavigateToProfile = { findNavController().navigate(R.id.nav_profile) })
}
}
}
Этот подход позволяет повторно использовать и тестировать composable-функции, поскольку они не зависят напрямую от NavController фрагмента.
Навигация с помощью NavDeepLinkRequest
Чтобы перейти к неявной ссылке на контент, используйте перегрузку navigate(NavDeepLinkRequest). Ниже приведен пример реализации этого метода.
Kotlin
val request = NavDeepLinkRequest.Builder
.fromUri("android-app://androidx.navigation.app/profile".toUri())
.build()
findNavController().navigate(request)
Java
NavDeepLinkRequest request = NavDeepLinkRequest.Builder
.fromUri(Uri.parse("android-app://androidx.navigation.app/profile"))
.build()
NavHostFragment.findNavController(this).navigate(request)
В отличие от навигации с использованием идентификаторов действий или пунктов назначения, вы можете перейти по любой ссылке на контент в своем графе, независимо от того, виден ли пункт назначения. Вы можете перейти к пункту назначения на текущем графике или на совершенно другом графике.
Действия и MIME-типы
Помимо Uri, NavDeepLinkRequest также поддерживает ссылки на контент с действиями и MIME-типами. Чтобы добавить действие в запрос, используйте fromAction() или setAction(). Чтобы добавить MIME-тип в запрос, используйте fromMimeType() или setMimeType().
Чтобы NavDeepLinkRequest правильно сопоставлялся с целевым объектом неявной ссылки на контент, URI, действие и MIME-тип должны соответствовать NavDeepLink в целевом объекте. URI должны соответствовать шаблону, действия должны точно совпадать, а MIME-типы должны быть связаны. Например, image/jpg соответствует image/\*.
Дополнительные контексты
В этом документе рассказывается, как использовать NavController.navigate() в наиболее распространенных случаях. Однако у функции есть ряд перегрузок, которые можно использовать в разных контекстах и в тандеме с любым фреймворком пользовательского интерфейса. Дополнительную информацию об этих перегрузках можно найти в справочной документации.
Дополнительные ресурсы
Дополнительную информацию можно найти на следующих страницах:
- Создание контроллера навигации
- Навигация и обратный стек
- Как настроить маршрут
- Типобезопасность в Kotlin DSL и Navigation Compose