Пользователи ожидают, что приложение будет состоять из нескольких экранов, а перемещение между ними окажется плавным и понятным. Раньше разработчикам приходилось вручную управлять транзакциями фрагментов и писать много служебного кода. Сегодня в Android Studio доступен специальный инструмент — Navigation Component, который позволяет описать карту переходов визуально и связать её с кодом на Kotlin. Этот урок научит вас создавать граф навигации, передавать данные и обрабатывать возврат на предыдущий шаг.
Что даёт Navigation Component
Jetpack Navigation решает три главные задачи: упрощает описание переходов, автоматически управляет back stack (стеком возврата) и обеспечивает типобезопасную передачу аргументов через Safe Args. Вместо того чтобы писать supportFragmentManager.beginTransaction().replace(...), вы просто вызываете метод findNavController().navigate(R.id.action), а всё остальное берёт на себя система. Граф навигации при этом выглядит как наглядная схема, доступная для редактирования прямо в редакторе.
Подключение библиотек
Для начала откройте build.gradle.kts модуля app и добавьте зависимости для Navigation Fragment и Navigation UI. На момент написания статьи актуальна версия 2.8.0, которая работает с Kotlin 2.x.
dependencies {
implementation("androidx.navigation:navigation-fragment-ktx:2.8.0")
implementation("androidx.navigation:navigation-ui-ktx:2.8.0")
}
В файле build.gradle.kts уровня проекта также добавьте плагин Safe Args для генерации классов аргументов:
plugins {
id("androidx.navigation.safeargs.kotlin") version "2.8.0" apply false
}
А в модуле app примените этот плагин:
plugins {
id("androidx.navigation.safeargs.kotlin")
}
После синхронизации Gradle можно переходить к созданию первого графа.
Создание навигационного графа
Навигационный граф — это XML-файл, в котором перечислены экраны (destinations) и связи между ними. Обычно его помещают в папку res/navigation/. Создайте файл nav_graph.xml, в котором определим два фрагмента: HomeFragment и DetailFragment, а также действие для перехода от первого ко второму.
<?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"
android:id="@+id/nav_graph"
app:startDestination="@id/homeFragment">
<fragment
android:id="@+id/homeFragment"
android:name="com.example.app.ui.HomeFragment"
android:label="Home">
<action
android:id="@+id/action_to_detail"
app:destination="@id/detailFragment" />
</fragment>
<fragment
android:id="@+id/detailFragment"
android:name="com.example.app.ui.DetailFragment"
android:label="Detail">
<argument
android:name="itemId"
app:argType="integer"
android:defaultValue="0" />
</fragment>
</navigation>
Атрибут startDestination указывает, какой фрагмент показывать при запуске. Через <argument> объявляется параметр, который можно передать из одного фрагмента в другой.
Размещение NavHostFragment в Activity
В разметке activity_main.xml добавьте контейнер FragmentContainerView — именно в нём будет происходить смена экранов. Укажите ему ссылку на граф навигации и задайте android:name="androidx.navigation.fragment.NavHostFragment".
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:navGraph="@navigation/nav_graph"
app:defaultNavHost="true" />
Параметр defaultNavHost="true" означает, что этот контейнер будет перехватывать системную кнопку «Назад» и обрабатывать её правильно.
Написание фрагментов на Kotlin
Теперь создадим два фрагмента. HomeFragment будет содержать кнопку, при нажатии на которую мы перейдём на DetailFragment с передачей аргумента.
class HomeFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_home, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
view.findViewById<Button>(R.id.btnNavigate).setOnClickListener {
val action = HomeFragmentDirections.actionToDetail(itemId = 42)
findNavController().navigate(action)
}
}
}
Класс HomeFragmentDirections сгенерирован плагином Safe Args автоматически на основе графа навигации. Он содержит метод, принимающий нужные аргументы и возвращающий объект действия.
Получение аргументов в DetailFragment
Во втором фрагменте используем тоже сгенерированный класс DetailFragmentArgs, чтобы извлечь переданный идентификатор.
class DetailFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_detail, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val args: DetailFragmentArgs by navArgs()
val itemId = args.itemId
view.findViewById<TextView>(R.id.tvDetail).text = "Item ID: $itemId"
}
}
Делегат navArgs() предоставляет готовый объект с параметрами, который можно сразу использовать.
Навигация назад и up-кнопка
Navigation автоматически управляет кнопкой «Назад» — при её нажатии фрагмент вернётся на предыдущий экран. Для верхней кнопки в Action Bar (стрелочка влево) достаточно связать контроллер с тулбаром через NavigationUI.setupActionBarWithNavController(this, navController). Это делается в onCreate Activity.
val navHostFragment = supportFragmentManager
.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController
NavigationUI.setupActionBarWithNavController(this, navController)
В результате на втором экране автоматически появится стрелка «вверх», ведущая обратно.
Итог
Сегодняшнее занятие в Android Studio показало, как при помощи языка Kotlin и Navigation Component можно выстроить чёткую схему переходов между фрагментами. Вы научились создавать граф навигации, передавать аргументы с использованием Safe Args и настраивать корректную обработку системной кнопки «Назад». Полученные навыки позволят вам делать многоэкранные приложения с предсказуемой навигацией, не тратя время на ручное управление транзакциями. Попробуйте добавить анимации переходов и условную навигацию — это естественное продолжение сегодняшнего урока.