Что такое 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