← Назад к вопросам

Как реализовать навигацию в Jetpack Compose?

2.0 Middle🔥 201 комментариев
#UI и вёрстка#Жизненный цикл и навигация

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Навигация в Jetpack Compose

Навигация в Jetpack Compose реализуется через Navigation Compose библиотеку, которая предоставляет компонентный подход к управлению маршрутами и стеком экранов.

1. Базовая установка

Прежде всего нужно добавить зависимость в build.gradle:

implementation "androidx.navigation:navigation-compose:2.7.x"

2. NavController и NavHost

Основные компоненты навигации:

@Composable
fun App() {
    val navController = rememberNavController()
    
    NavHost(
        navController = navController,
        startDestination = "home"
    ) {
        composable("home") { HomeScreen(navController) }
        composable("details/{id}") { backStackEntry ->
            val id = backStackEntry.arguments?.getString("id")
            DetailsScreen(id = id, navController = navController)
        }
    }
}

NavController управляет навигацией и содержит информацию о текущем маршруте. NavHost это контейнер, отображающий компонент в зависимости от текущего маршрута.

3. Типизированная навигация с Route

Вместо строк лучше использовать sealed class или data class для типобезопасности:

sealed class Route {
    data object Home : Route()
    data class Details(val id: String) : Route()
    data object Settings : Route()
}

@Composable
fun App() {
    val navController = rememberNavController()
    
    NavHost(
        navController = navController,
        startDestination = Route.Home
    ) {
        composable<Route.Home> {
            HomeScreen(
                onNavigate = { route -> navController.navigate(route) }
            )
        }
        composable<Route.Details> { backStackEntry ->
            val args = backStackEntry.toRoute<Route.Details>()
            DetailsScreen(id = args.id)
        }
    }
}

4. Навигация между экранами

Основные операции навигации:

// Переход на новый экран
navController.navigate(Route.Details(id = "123"))

// С сохранением в backstack
navController.navigate(Route.Home) {
    popUpTo(Route.Details) { inclusive = true }
}

// Возврат назад
navController.popBackStack()

// Очистить весь backstack
navController.popBackStack(Route.Home, inclusive = false)

5. Передача аргументов

Передача данных между экранами:

@Composable
fun HomeScreen(onNavigate: (Route) -> Unit) {
    Button(
        onClick = {
            onNavigate(Route.Details(id = "user123"))
        }
    ) {
        Text("Go to Details")
    }
}

@Composable
fun DetailsScreen(id: String) {
    Text("Showing details for: $id")
}

6. Deep Links

Поддержка deep links для открытия приложения с определённого экрана:

navigraphmodule/
composable<Route.Details>(
    deepLinks = listOf(
        navDeepLink<Route.Details>("https://example.com/details/{id}")
    )
) { backStackEntry ->
    val args = backStackEntry.toRoute<Route.Details>()
    DetailsScreen(id = args.id)
}

7. Сохранение состояния при навигации

По умолчанию Compose пересоздаёт компоненты при навигации. Для сохранения состояния:

NavHost(
    navController = navController,
    startDestination = Route.Home
) {
    composable<Route.Home>(
        enterTransition = { fadeIn() },
        exitTransition = { fadeOut() }
    ) {
        HomeScreen()
    }
}

8. Вложенная навигация (Nested Navigation)

Для сложных приложений с несколькими потоками (home, search, profile):

NavHost(navController, startDestination = "home") {
    navigation<Route.Home>(startDestination = Route.HomeMain) {
        composable<Route.HomeMain> { HomeScreen() }
        composable<Route.HomeDetails> { DetailsScreen() }
    }
    navigation<Route.Profile>(startDestination = Route.ProfileMain) {
        composable<Route.ProfileMain> { ProfileScreen() }
    }
}

9. ViewModel и Hilt с навигацией

Использование ViewModel, который сохраняет состояние при пересоздании композитов:

@HiltViewModel
class DetailsViewModel @Inject constructor(
    val repository: Repository
) : ViewModel() {
    val uiState = mutableStateOf<UiState>(UiState.Loading)
}

@Composable
fun DetailsScreen(
    viewModel: DetailsViewModel = hiltViewModel()
) {
    // viewModel сохранится при навигации
}

Best Practices

  • Используйте типизированные маршруты вместо строк
  • Держите ViewModel в памяти при поп-бэке
  • Избегайте перемещения слишком большого количества данных между маршрутами
  • Используйте SavedStateHandle для сохранения состояния
  • Правильно обрабатывайте backstack при нескольких потоках навигации