Как организовать экраны и перелистывание в Android

Короткий ответ: Navigation — для маршрутов и back‑stack, ViewPager2 — для локального перелистывания страниц; чаще всего лучшая схема — NavHost на уровне Activity и ViewPager2 внутри отдельных фрагментов, а состояние хранить в ViewModel.

Когда нужен ViewPager2, а когда Navigation

  • Navigation (Jetpack) нужен, если нужен прозрачный стек экранов, deep links, Safe Args и корректная обработка Back.
  • ViewPager2 подходит, когда пользователь ожидает свайп: онбординг, галереи, карточки, горизонтальные ленты.
  • Если "pager" — это последовательность шагов с ветвлением логики (условные переходы, пропуски), лучше реализовать каждый шаг как отдельный фрагмент в навграфе.

Типичная ошибка — строить сложный многошаговый поток (регистрация, checkout) целиком на ViewPager2: потом сложно поддерживать возвраты, ветвления и состояние.

Практические схемы сочетания и примеры

  1. ViewPager2 внутри одного фрагмента (onboarding, слайды)
  • Навигатор знает только OnboardingFragment как один экран.
  • Внутри него ViewPager2 показывает слайды (фрагменты или View).
  • Обработка системной кнопки Back делается локально: если currentItem > 0 — листаем назад, иначе вызываем стандартный onBackPressed.

Пример обработки Back (кратко):

requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) {
  if (viewPager.currentItem > 0) viewPager.currentItem -= 1
  else { isEnabled = false; requireActivity().onBackPressedDispatcher.onBackPressed() }
}
  1. Навигация на верхнем уровне + ViewPager2 внутри таба
  • Одна Activity с NavHostFragment.
  • Навграф описывает верхние разделы (Home, Profile...). Внутри HomeFragment может быть ViewPager2 для локального перелистывания контента.
  • Такой подход сохраняет понятный стек и позволяет иметь отдельные состояния для каждого таба.
  1. Полный отказ от ViewPager2, если нужен back‑stack на каждый шаг
  • Создавайте отдельные фрагменты в nav_graph и используйте кастомные анимации slide_in/slide_out, чтобы имитировать свайп.
  • Это даёт корректный back‑stack и поддержку deep links.

Храните логику и состояние в ViewModel, а не во фрагментах ViewPager2 — это существенно упрощает сохранение состояния и тестирование.

Настройки и подводные камни ViewPager2

  • isUserInputEnabled — включить/отключить свайп.
  • offscreenPageLimit — сколько страниц держать в памяти (баланс памать/плавность).
  • Не помещайте в pager очень тяжёлые фрагменты с картами и множ. списками — лучше навигация + отдельные фрагменты.

Частые ошибки

  • Пытаться реализовать всю навигацию приложения внутри ViewPager2.
  • Игнорировать системный Back для pager‑страниц.
  • Дублировать логику навигации в разных местах вместо вынесения в NavGraph.
  • Хранить состояние только в фрагментах — при пересоздании теряются данные.

FAQ

  • Нужно ли использовать несколько Activity? Обычно достаточно одной Activity + NavHost.
  • Можно ли вложить NavHost внутри ViewPager2? Да, но избегайте сложных nested NavHost без явной нужды — это усложняет жизненный цикл и навигацию.
  • Как сделать переход от онбординга в основной граф? Навигируйте из OnboardingFragment в целевой фрагмент через findNavController().navigate(action).

Следуйте простой формуле: Navigation управляет маршрутизацией и стеком, ViewPager2 — отображением соседних страниц внутри экрана. Совмещайте их тогда, когда задача чётко разделяется на «маршруты» и «локальное перелистывание».