Прямые ссылки на публичные уроки для быстрого старта и стабильной индексации lesson-страниц.
На прошлом уроке мы разобрали "чистую" навигацию через переменную currentScreen и выяснили, что ручное управление состоянием экрана быстро становится неудобным для реальных приложений. Теперь используем официальную библиотеку Navigation Compose — промышленное решение, где экраны плавно переключаются, передают данные и корректно возвращаются назад.
Подключаем библиотеку в build.gradle.kts. Версии хранятся в каталоге .toml — добавляем туда новую строку в разделе с библиотеками:
androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "composeNavigation" }
Затем ссылаемся на неё в build.gradle.kts:
implementation(libs.androidx.navigation.compose)
Синхронизируем проект — библиотека подключена.
Основная идея: есть NavController, который хранит состояние навигационного стека и переключается между "маршрутами" (destinations). Вместо XML-графа экраны (routes) объявляются прямо в коде Kotlin внутри NavHost. Роуты хранятся в виде обычных строк.
Для правильной архитектуры создадим несколько дополнительных файлов в отдельном пакете navigation.
Создаём класс с роутами — Destination. Объявляем sealed класс с двумя роутами в виде data object. Константы роутов выносим в companion object.
Почему sealed? Все наследники должны быть объявлены в одном файле — мы всегда видим полный список маршрутов, добавить недопустимый подкласс извне невозможно.
sealed class Destination(val route: String) { data object First : Destination(ROUTE_FIRST) data object Second : Destination(ROUTE_SECOND) companion object { private const val ROUTE_FIRST = "route_first" private const val ROUTE_SECOND = "route_second" } }
Создаём файл AppNavHost.kt с функцией AppNavHost, принимающей navController:
@Composable fun AppNavHost( navController: NavHostController, ) { }
AppNavHost — точка настройки навигации приложения:
1. Связывает NavController с NavHost (контейнером, отрисовывающим экраны).
2. Объявляет маршруты и логику переходов.
3. Указывает начальный экран startDestination).
NavHostController управляет стеком экранов и переходами: navigate(route) переключает экран, popBackStack() возвращает на предыдущий.
NavHost — контейнер, отрисовывающий экран по текущему маршруту из navController. Обязательные параметры: NavHostController и startDestination.
@Composable fun AppNavHost( navController: NavHostController, ) { NavHost( navController = navController, startDestination = Destination.First.route, ) { } }
Экраны добавляются функциями composable. Каждая связана с определённым маршрутом route). В необязательных параметрах реализуется передача аргументов, диплинки и анимации переходов.
Логика переходов: FirstScreen принимает коллбэк onClickButton, внутри которого вызывается navigate с роутом второго экрана. Для второго экрана вызываем popBackStack() — имитация нажатия кнопки "Назад". Всю работу с бэкстеком библиотека делает под капотом.
@Composable fun AppNavHost( navController: NavHostController, ) { NavHost( navController = navController, startDestination = Destination.First.route, ) { composable(route = Destination.First.route) { FirstScreen(onClickButton = { navController.navigate(Destination.Second.route) }) } composable(route = Destination.Second.route) { SecondScreen(onClickButton = { navController.popBackStack() }) } } }
В MainActivity вызываем AppNavHost внутри Box, чтобы ко всем экранам применялся innerPadding. NavHostController создаётся через rememberNavController() и передаётся в качестве параметра.
setContent { MyApplicationTheme { Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> Box( modifier = Modifier.padding(innerPadding) ) { val navController = rememberNavController() AppNavHost(navController = navController) } } } }
Навигация заработала. Переходы стали плавными — появились стандартные анимации. На втором экране кнопка "Назад" возвращает на первый экран, а не выходит из приложения.
AppNavHost.NavHost структура навигации читается в одном файле: сразу видно, какие маршруты есть и как они связаны.