Navigation Component для Kotlin: полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Что такое Navigation Component и зачем он нужен

Navigation Component — это библиотека от Google для Android, предназначенная для упрощения навигации между экранами (фрагментами, Activity, диалогами) в приложениях на Kotlin и Java. Она является частью Android Jetpack и предоставляет единый, предсказуемый способ управления переходами, обработки аргументов и работы с кнопкой "Назад".

Зачем это нужно? Без Navigation Component разработчики часто писали много шаблонного кода: создавали FragmentManager, обрабатывали BackStack, передавали данные через Bundle и следили за состоянием переходов. Библиотека решает эти проблемы, предлагая:

  • Визуальный редактор навигации — граф переходов в XML.
  • Безопасную передачу аргументов через Safe Args (плагин Gradle).
  • Автоматическое управление BackStack — кнопка "Назад" работает корректно.
  • Глубокие ссылки (Deep Links) — переходы из уведомлений или внешних ссылок.
  • Анимации переходов — простые настройки в XML.

Установка Navigation Component

Поскольку Navigation Component — это библиотека для Android, установка происходит через систему сборки Gradle, а не через pip или npm. Добавьте зависимости в файл build.gradle (уровень модуля, обычно app/build.gradle):

// build.gradle (Module: app)
plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
    id 'androidx.navigation.safeargs.kotlin' // для Safe Args
}

android {
    // ... стандартные настройки
}

dependencies {
    implementation 'androidx.navigation:navigation-fragment-ktx:2.7.7'
    implementation 'androidx.navigation:navigation-ui-ktx:2.7.7'
    // Для работы с динамическими фичами (Feature Modules)
    implementation 'androidx.navigation:navigation-dynamic-features-fragment:2.7.7'
}

Также убедитесь, что в корневом build.gradle добавлен плагин Safe Args:

// build.gradle (Project level)
plugins {
    id 'androidx.navigation.safeargs.kotlin' version '2.7.7' apply false
}

После синхронизации Gradle библиотека готова к использованию.

Быстрый старт с примером кода

Создадим простое приложение с двумя экранами: HomeFragment и DetailFragment. Пользователь нажимает кнопку на первом экране и переходит на второй, передавая строку.

Шаг 1: Создайте файл навигации

В папке res/navigation создайте файл nav_graph.xml:

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/nav_graph"
    app:startDestination="@id/homeFragment">

    <fragment
        android:id="@+id/homeFragment"
        android:name="com.example.app.HomeFragment"
        android:label="Home"
        tools:layout="@layout/fragment_home">
        <action
            android:id="@+id/action_homeFragment_to_detailFragment"
            app:destination="@id/detailFragment" />
    </fragment>

    <fragment
        android:id="@+id/detailFragment"
        android:name="com.example.app.DetailFragment"
        android:label="Detail"
        tools:layout="@layout/fragment_detail">
        <argument
            android:name="message"
            app:argType="string" />
    </fragment>
</navigation>

Шаг 2: Настройте Activity

В activity_main.xml добавьте NavHostFragment:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:defaultNavHost="true"
        app:navGraph="@navigation/nav_graph" />
</androidx.constraintlayout.widget.ConstraintLayout>

Шаг 3: Реализуйте фрагменты

HomeFragment.kt:

class HomeFragment : Fragment() {
    private lateinit var binding: FragmentHomeBinding

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = FragmentHomeBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        binding.buttonGoToDetail.setOnClickListener {
            val action = HomeFragmentDirections.actionHomeFragmentToDetailFragment("Привет из Home!")
            findNavController().navigate(action)
        }
    }
}

DetailFragment.kt:

class DetailFragment : Fragment() {
    private lateinit var binding: FragmentDetailBinding

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = FragmentDetailBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        // Получаем аргументы через Safe Args
        val message = arguments?.getString("message") ?: "Нет сообщения"
        binding.textViewMessage.text = message
    }
}

Готово! При нажатии на кнопку происходит переход с передачей данных.

Основные методы и функции Navigation Component

Ниже приведены ключевые методы библиотеки, которые используются чаще всего. Все примеры написаны на Kotlin.

1. findNavController()

Что делает: Возвращает NavController, связанный с текущим View, Fragment или Activity. Это главный объект для выполнения навигации.

Параметры: Принимает View, Fragment или Activity (в виде расширения).

Пример:

// Внутри Fragment
val navController = findNavController()

// Внутри Activity
val navController = findNavController(R.id.nav_host_fragment)

// Внутри View (например, из кастомного View)
val navController = Navigation.findNavController(view)

2. navigate()

Что делает: Выполняет переход к указанному пункту назначения. Может принимать ID действия (action) из nav_graph или ID фрагмента/Activity.

Параметры:

  • @IdRes int resId — ID ресурса (действие или пункт назначения).
  • Bundle? args — аргументы для передачи (опционально).
  • NavOptions? navOptions — параметры навигации (анимация, pop-поведение).
  • Navigator.Extras? navigatorExtras — дополнительные опции (для shared elements).

Пример:

// Простой переход по ID действия
findNavController().navigate(R.id.action_homeFragment_to_detailFragment)

// Переход с аргументами
val bundle = Bundle().apply {
    putString("key", "value")
}
findNavController().navigate(R.id.detailFragment, bundle)

// Переход с анимацией
val navOptions = navOptions {
    anim {
        enter = R.anim.slide_in_right
        exit = R.anim.slide_out_left
        popEnter = R.anim.slide_in_left
        popExit = R.anim.slide_out_right
    }
}
findNavController().navigate(R.id.detailFragment, null, navOptions)

3. navigateUp()

Что делает: Возвращает на предыдущий экран (аналог кнопки "Назад"). Работает корректно с BackStack.

Параметры: Нет.

Пример:

// Обработка нажатия кнопки "Назад" в тулбаре
binding.toolbar.setNavigationOnClickListener {
    findNavController().navigateUp()
}

// Или просто вызвать в любом месте
findNavController().navigateUp()

4. popBackStack()

Что делает: Удаляет текущий пункт назначения из BackStack и возвращает к предыдущему. Можно указать, до какого именно пункта нужно "откатить" стек.

Параметры:

  • @IdRes int destinationId — ID пункта, до которого нужно очистить стек (опционально).
  • boolean inclusive — если true, удаляет и указанный пункт тоже.

Пример:

// Просто вернуться назад
findNavController().popBackStack()

// Вернуться к HomeFragment, удалив все промежуточные экраны
findNavController().popBackStack(R.id.homeFragment, false)

// Вернуться к HomeFragment и удалить его тоже (уйдем еще дальше)
findNavController().popBackStack(R.id.homeFragment, true)

5. currentDestination

Что делает: Возвращает текущий пункт назначения (NavDestination), на котором находится пользователь. Полезно для проверки, не выполнять лишних переходов.

Параметры: Нет (свойство).

Пример:

val currentDest = findNavController().currentDestination
if (currentDest?.id == R.id.detailFragment) {
    // Пользователь уже на DetailFragment, не делаем повторный переход
    return
}
findNavController().navigate(R.id.detailFragment)

6. setGraph()

Что делает: Устанавливает граф навигации для NavController. Обычно используется при программной настройке NavHostFragment.

Параметры:

  • @NavigationRes int graphResId — ID ресурса графа.
  • Bundle? startDestinationArgs — аргументы для стартового пункта (опционально).

Пример:

// В Activity, если вы создаете NavHostFragment программно
val navHostFragment = supportFragmentManager
    .findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController

val args = Bundle().apply {
    putString("userId", "123")
}
navController.setGraph(R.navigation.nav_graph, args)

7. getBackStackEntry()

Что делает: Возвращает NavBackStackEntry для указанного пункта назначения в BackStack. Позволяет получить аргументы или состояние предыдущего экрана.

Параметры:

  • @IdRes int destinationId — ID пункта назначения.

Пример:

// Получить аргументы из HomeFragment, если мы сейчас на DetailFragment
val backStackEntry = findNavController().getBackStackEntry(R.id.homeFragment)
val message = backStackEntry.arguments?.getString("message")
Log.d("Navigation", "Сообщение из Home: $message")

8. addOnDestinationChangedListener()

Что делает: Добавляет слушатель, который вызывается каждый раз при изменении текущего пункта назначения. Полезно для аналитики, обновления UI (например, заголовка тулбара).

Параметры:

  • NavController.OnDestinationChangedListener listener — слушатель с тремя параметрами: controller, destination, arguments.

Пример:

findNavController().addOnDestinationChangedListener { _, destination, _ ->
    when (destination.id) {
        R.id.homeFragment -> binding.toolbar.title = "Главная"
        R.id.detailFragment -> binding.toolbar.title = "Детали"
        else -> binding.toolbar.title                    

Рекомендаций