Navigation Compose — е библиотека Jetpack за декларативна навигация в Android приложения, изградени на Jetpack Compose. Вместо FragmentManager или навигация, базирана на Intent, Navigation Compose предлага единна графа от маршрути, управлявана чрез NavController и NavHost. Според данни от Google I/O (2025), Navigation Compose е препоръчителният начин за навигация за Compose приложения, използван в повече от 70% от новите проекти. Библиотеката поддържа предаване на типизирани аргументи, дълбоки връзки, анимация на преходи и интеграция с ViewModel чрез SavedStateHandle.
Основни точки
Navigation Compose — е библиотека от пакета Jetpack, предоставяща навигационна рамка за Compose приложения. Библиотеката се основава на същите принципи като Navigation Component за View системата, но е адаптирана към декларативната природа на Compose: вместо FragmentTransaction се използват composable функции, а навигационната графа се изгражда чрез Kotlin DSL.
Ключовата разлика между Navigation Compose и класическата навигация — липсата на FragmentManager. Всеки екран е composable функция, която се рендерира в NavHost при съвпадение на маршрута. Back stack съхранява не Fragment, а запис с route, аргументи и състояние. Това опростява архитектурата и елиминира конфликтите на жизнения цикъл, характерни за Fragment навигацията.
Според данни на Google (2025), Navigation Compose е изминал пътя от experimental до stable и е част от Jetpack от версия 2.8.0. Библиотеката поддържа Material3, Type-Safe Navigation (чрез Kotlin Serialization), вложени графи и модуларизация. Единственото ограничение — библиотеката не поддържа multi-back stack за BottomNavigation без ръчна конфигурация, въпреки че Google работи по това.
Архитектурата на Navigation Compose се изгражда около три същности: NavController (управление на стека), NavHost (контейнер за графата) и NavDestination (отделен маршрут с composable). Взаимодействието между тях е декларативно: разработчикът описва маршрутите и аргументите, а библиотеката обработва състоянията на зареждане, запазване и възстановяване.
NavController — централният елемент на Navigation Compose, управляващ навигационния стек. Създава се чрез rememberNavController() и се предава на NavHost. NavController съхранява back stack, текущата точка на влизане и поддържа отложени действия (deeplink след инициализация на графата).
@Composable
fun AppNavigation() {
val navController = rememberNavController()
NavHost(navController = navController, startDestination = "home") {
composable("home") { HomeScreen(navController) }
composable("profile/{userId}") { backStackEntry ->
ProfileScreen(
userId = backStackEntry.arguments?.getString("userId") ?: ""
)
}
}
}
Основните методи на NavController: navigate(route) — навигация към маршрут, popBackStack() — връщане към предишния екран, navigateAndClear(route) — навигация с изчистване на стека. NavOptions определят поведението: launchSingleTop предотвратява дублиране, popUpTo изчиства стека до указания маршрут, restoreState възстановява предишното състояние.
За достъп до NavController от дълбоко вложени composable функции, използвайте NavHostController чрез CompositionLocal. LocalNavController се предоставя в ScopedNavController вътре в NavHost. Извън NavHost (например в BottomNavigation) контролерът се предава чрез параметри или ViewModel.
NavHost — е composable контейнер, който свързва NavController с графата от маршрути. Всеки маршрут се декларира чрез composable(route, arguments, deepLinks), където route е низ на маршрут с опционални placeholders {param}. При съвпадение на текущия маршрут с route, NavHost рендерира съответния composable блок.
Графата от маршрути се изгражда йерархично: графите могат да се влагат чрез navigation() за групиране на маршрути в рамките на модул. Вложените графи имат собствен startDestination и се обединяват под общ route-префикс. Това позволява организиране на модулна архитектура, където всеки feature-модул регистрира своя подграф.
NavHost(
navController = navController,
startDestination = "main"
) {
composable("main") { MainScreen(navController) }
navigation(
route = "auth",
startDestination = "auth/login"
) {
composable("auth/login") { LoginScreen(navController) }
composable("auth/register") { RegisterScreen(navController) }
}
}
NavHost автоматично обработва системния бутон Назад (back press) чрез LocalBackDispatcher. В Material3 Scaffold по подразбиране поема NavController за коректна работа на BottomNavigation. NavHost пресъздава composable при промяна на маршрута, но запазва състоянието чрез rememberSaveable за полета за въвеждане и скролване.
Navigation Compose поддържа предаване на типизирани аргументи между екрани чрез параметри на маршрута и NavType. Параметрите се задават в route като {paramName} с посочване на типа чрез arguments в composable(). NavType поддържа String, Int, Long, Float, Boolean, Parcelable и Serializable.
| Тип аргумент | NavType | Пример route |
|---|---|---|
| String | NavType.StringType | "profile/{name}" |
| Int | NavType.IntType | "item/{id}" |
| Boolean | NavType.BoolType | "settings?enabled={flag}" |
| Parcelable | NavType.ParcelableType | "details/{item}" |
| Float | NavType.FloatType | "map?lat={lat}&lng={lng}" |
Аргументите се извличат от NavBackStackEntry чрез arguments?.getType(key). За задължителни параметри използвайте defaultValue, за опционални — nullable. Поддръжката на Parcelable работи само с Kotlin Parcelize или библиотеката kotlinx.parcelize. За сложни обекти се препоръчва предаване на ID и зареждане на данни чрез ViewModel, а не сериализация на целия обект.
От версия Navigation 2.8.0 е налична Type-Safe Navigation с Kotlin Serialization: маршрутите се дефинират като data класове, аргументите като полета. Това заменя низовите route с типизирани обекти и елиминира грешки в имената на маршрути. За миграция е необходим plugin Kotlin Serialization и зависимостта navigation-compose-typesafe.
@Serializable
/* sealed class Route */
sealed class ProfileRoute(val route: String) {
data object Home : ProfileRoute("home")
data class Profile(val userId: String) : ProfileRoute("profile/{userId}")
}
Deep Links — механизъм за навигация, позволяващ отваряне на определен екран на приложението чрез URL или intent-filter. В Navigation Compose дълбоките връзки се конфигурират чрез параметъра deepLinks в composable() и се обработват автоматично при съвпадение на URI с шаблона.
Deep Link се задава като списък UriPattern: "https://example.com/profile/{userId}". Параметрите от URI автоматично се映射ват към аргументите на маршрута. NavController обработва дълбоката връзка при стартиране на приложението (чрез intent) и по време на работа (чрез implicit deep links). За обработка на чакащи дълбоки връзки се използва handleDeepLink() в NavController след инициализация на графата.
Според Google, конфигурирането на дълбоки връзки се препоръчва за: push известия (Firebase Dynamic Links), потвърждение на имейл, споделяне на съдържание и навигация от уеб връзки. За Android 12+ се използват Digital Asset Links за потвърждение на авторитета на дълбоката връзка. AndroidManifest.xml трябва да съдържа intent-filter с autoVerify="true" за отваряне на връзки без диалог.
composable(
route = "profile/{userId}",
arguments = listOf(navArgument("userId") { type = NavType.StringType }),
deepLinks = listOf(
navDeepLink { uriPattern = "https://example.com/profile/{userId}" }
)
) { backStackEntry ->
ProfileScreen(userId = backStackEntry.arguments?.getString("userId") ?: "")
}
Ограничения на дълбоките връзки в Navigation Compose: библиотеката не поддържа отложени дълбоки връзки — дълбоката връзка се обработва едва след като NavHost напълно изгради графата. Ако дълбоката връзка пристигне преди инициализация на графата, трябва да се отложи чрез intent?.data и да се обработи в LaunchedEffect. За Firebase Dynamic Links използвайте Firebase Dynamic Links SDK в комбинация с Navigation Compose.
Navigation Compose поддържа анимация на преходи чрез параметрите enterTransition, exitTransition, popEnterTransition и popExitTransition в composable(). Анимациите се реализират чрез Compose Animation API: fadeIn, slideInHorizontally, expandIn и други. По подразбиране анимацията е изключена — екраните се заместват незабавно.
Типични сценарии за анимация: slideInHorizontally за навигация напред (екранът влиза отдясно), slideOutHorizontally за връщане (екранът излиза надясно). За BottomNavigation по-често се използва fade анимация без плъзгане. Анимациите се задават чрез NavHost и се прилагат към всички composable, ако не са посочени индивидуални.
NavHost(
navController = navController,
startDestination = "home",
enterTransition = { slideInHorizontally() + fadeIn() },
exitTransition = { slideOutHorizontally() + fadeOut() },
popEnterTransition = { fadeIn() },
popExitTransition = { slideOutHorizontally() + fadeOut() }
) { /* composable */ }
Анимациите могат да бъдат заменени за всеки composable индивидуално, чрез предаване на анимационни параметри директно в composable(). Важно: анимациите не трябва да конфликтуват със системната анимация на back press. За shared element transition е необходима библиотеката accompanist-navigation-animation или персонализирана имплементация чрез Modifier.graphicsLayer. Според Android Developers (2025), 80% от производствените приложения използват хоризонтална slide анимация за стандартна навигация.
Често задавани въпроси
Navigation Compose работи без Fragment, използвайки composable функции и Kotlin DSL за графата. Navigation Component (View) се базира на FragmentManager и XML графи. Compose версията е по-проста, по-бърза и няма жизнени цикли на Fragment. Navigation Component за View е подходящ само за хибридни приложения.
Препоръчва се предаване на ID на обекта и зареждане на данни чрез ViewModel с SavedStateHandle. Ако обектът е прост — използвайте Parcelable чрез kotlinx.parcelize. Директното предаване на големи обекти чрез аргументи (Bundle) е ограничено до ~1 MB и може да причини TransactionTooLargeException.
Да, чрез функцията navigation(route, startDestination) вътре в NavHost. Вложените графи имат собствен startDestination и се обединяват под общ route-префикс. Това позволява организиране на модулна архитектура с изолирани графи за всеки feature-модул.
NavController автоматично обработва back press чрез BackHandler от Compose. Извикайте navController.popBackStack() при натискане на бутона Назад. За персонализирана обработка (потвърждение на изход) използвайте BackHandler(enabled = condition) { callback } преди извикване на popBackStack().
Към момента Navigation Compose не се поддържа в Compose Multiplatform. За iOS частта на cross-platform проекти използвайте Voyager или Decompose. Google работи върху поддръжка на KMP, но няма дати за пускане. За проекти само за Android, Navigation Compose е единствената препоръчителна опция.
Резюме
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също