Route — что это, типы и создание маршрутов в Flutter

Автор: IT Sectr Опубликовано: 2026-07-02 Время чтения: 8 мин

Route — это абстрактный класс во Flutter, представляющий отдельный экран или страницу в навигационной истории Navigator. Конкретные реализации Route — MaterialPageRoute, CupertinoPageRoute и PlatformRoute — определяют, как экран отображается и какая анимация используется при переходе. В отличие от обычного виджета, Route имеет собственный жизненный цикл с методами didPush, didPop, didReplace и didChangeNext. По данным Flutter API Reference (2026), каждый Route управляет ModalBarrier, учитывает платформенные особенности (свайп-назад на iOS) и обеспечивает изоляцию состояния между экранами.

Главное

  • Route — абстрактный класс экрана во Flutter с собственным жизненным циклом (didPush, didPop, didReplace, didChangeNext)
  • MaterialPageRoute — стандартная реализация Route с Material-анимацией (слайд снизу) для Android и десктопа
  • CupertinoPageRoute — реализация Route с iOS-анимацией (слайд справа + свайп-назад жестом) для iPhone и iPad
  • Жизненный цикл — Route проходит стадии: переход (Transition), показ (Active), скрытие (Inactive) и уничтожение (Disposed)
  • Передача данных — Route принимает аргументы через конструктор и возвращает результат через Future при завершении

Что такое Route во Flutter

Route — это основа навигационной системы Flutter. Каждый экран, который пользователь видит в приложении, представлен объектом Route, находящимся в стеке Navigator. Route абстрагирует экран от управляющего кода: Navigator добавляет и удаляет Route, а внутри Route находится интерфейс, который видит пользователь. Такая архитектура разделяет ответственность между навигацией и отображением.

В отличие от простой замены виджетов, Route предоставляет сервисы, недоступные обычным виджетам: ModalBarrier (затенение фона при открытом диалоге), управление анимацией входа и выхода, обработка аппаратной кнопки «Назад» на Android и интеграция с Hero-анимацией для плавных переходов между экранами.

По данным Flutter Cookbook (2026), Route является ключевым элементом для Hero-анимации: Hero-виджет на одном Route автоматически анимирует переход к Hero-виджету на следующем Route, создавая эффект «летящего» элемента. Это возможно именно потому, что Route сохраняет оба экрана в Overlay во время анимации.

Route как строительный блок навигации

Route является основой как для простых мобильных приложений (через Navigator 1.0), так и для сложных сценариев с глубокими ссылками (Navigator 2.0). В Navigator 2.0 Route представляет собой Page, который RouterDelegate конвертирует из конфигурации маршрута. Таким образом, понимание Route необходимо для работы с любой системой навигации Flutter — независимо от выбранного подхода или пакета.

Типы Route: MaterialPageRoute и CupertinoPageRoute

Flutter предоставляет несколько встроенных реализаций Route, каждая из которых адаптирует поведение под конкретную платформу. Выбор правильного типа Route влияет на пользовательский опыт: Material-анимация на Android и Cupertino-анимация на iOS создают ощущение «родного» приложения.

Тип RouteАнимацияПлатформаОсобенности
MaterialPageRouteСлайд снизу вверхAndroid, десктопТень при переходе, автоматическая обработка SafeArea
CupertinoPageRouteСлайд справа налевоiOS, iPadOSСвайп-назад жестом, прозрачный фон при переходе
PlatformRouteАвтоматический выборВсе платформыВыбирает тип на основе TargetPlatform
PageRouteBuilderКастомнаяВсе платформыПолный контроль над анимацией через AnimationController

MaterialPageRoute: стандарт для Android

MaterialPageRoute — наиболее часто используемая реализация Route. Она анимирует вход нового экрана снизу вверх с постепенным появлением. При выходе экран анимируется сверху вниз, возвращаясь в исходное положение. Панель инструментов (AppBar) и тело экрана анимируются раздельно, создавая эффект иерархии.

CupertinoPageRoute: iOS-стиль навигации

CupertinoPageRoute имитирует UINavigationController из iOS. Новый экран въезжает справа, закрывая предыдущий. Ключевая особенность — поддержка интерактивного свайп-назад жестом, которая реализована через CupertinoBackGestureDetector. Этот жест обрабатывается даже в середине анимации, обеспечивая естественное поведение, знакомое пользователям iPhone.

Жизненный цикл Route: от создания до уничтожения

Route имеет собственный жизненный цикл, который отличается от жизненного цикла обычного StatefulWidget. Понимание этого цикла необходимо для правильной инициализации данных, подписки на стримы и освобождения ресурсов при закрытии экрана.

Стадии жизненного цикла Route

Жизненный цикл Route состоит из четырёх основных стадий. Transition — Route создаётся и анимируется при входе (вызывается didPush). Active — Route полностью отображается и взаимодействует с пользователем. Inactive — другой Route перекрывает текущий (диалог, нижний экран), но Route остаётся в стеке. Disposed — Route удаляется из стека и уничтожается, вызывается didPop и dispose.

Методы жизненного цикла Route могут быть переопределены в кастомной реализации. Например, didPop вызывается, когда Route удаляется из стека — здесь можно сохранить черновик данных. didChangeNext вызывается, когда следующий Route в стеке изменился — полезно для обновления UI при изменении истории навигации.

По данным Flutter API Route.didPop (2026), важно не путать жизненный цикл Route с жизненным циклом State внутри Route. StatefulWidget внутри Route имеет собственный initState и dispose, которые вызываются в рамках стадии Transition и Disposed соответственно. Route живёт дольше, чем его внутренний State — Route остаётся в Overlay даже когда его виджеты временно скрыты другим Route.

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

Route предоставляет механизмы для передачи данных как на вход (при создании), так и на выход (при завершении). Правильная передача данных через Route избавляет от глобальных переменных и InheritedWidget, делая навигацию типобезопасной и предсказуемой.

Для передачи данных на новый экран используется конструктор принимающего виджета или аргумент arguments в Navigator.pushNamed. Внутри Route данные доступны через RouteSettings.arguments, который хранится в объекте Route. Этот подход работает для всех типов Route — MaterialPageRoute, CupertinoPageRoute и кастомных реализаций.

Для возврата данных используется второй аргумент Navigator.pop(context, result). Navigator.push возвращает Future<Т>, которая завершается со значением, переданным в pop. Если pop вызван без аргумента, Future завершается с null. Этот механизм — аналог startActivityForResult в Android и completion handler в iOS, но реализованный через Dart Futures.

Пример передачи данных через конструктор Route

При прямом вызове Navigator.push с MaterialPageRoute данные передаются через конструктор целевого экрана. MethodChannel не используется — это чистое Dart-взаимодействие. Такой подход предпочтителен для типобезопасной передачи сложных объектов.

Пример создания кастомного Route

Рассмотрим пример создания кастомного Route с собственной анимацией и передачей данных. PageRouteBuilder позволяет определить анимацию входа и выхода с полным контролем над кривой анимации и длительностью.

dart
// Custom Route with slide animation
Navigator.push(context, PageRouteBuilder(
  pageBuilder: (context, animation, secondaryAnimation) {
    return DetailPage(productId: '42');
  },
  transitionsBuilder: (context, animation, secondaryAnimation, child) {
    const begin = Offset(0.0, 0.3);
    const end = Offset.zero;
    final tween = Tween(begin: begin, end: end);
    final offsetAnimation = animation.drive(tween);
    return SlideTransition(position: offsetAnimation, child: child);
  },
  transitionDuration: const Duration(milliseconds: 400),
));

// Return data from screen
ElevatedButton(
  onPressed: () => Navigator.of(context).pop({'selected': true, 'id': '42'}),
  child: const Text('Select'),
);

// Get result on calling screen
final result = await Navigator.push(context, MaterialPageRoute(
  builder: (context) => const SelectionPage(),
));
if (result != null) {
  print('Selected: ${result['selected']}');
}

В примере PageRouteBuilder определяет кастомную анимацию слайда снизу с прозрачностью. transitionDuration задаёт скорость анимации. Код также демонстрирует передачу результата: детальный экран возвращает Map с выбором пользователя, а вызывающий экран получает эти данные через Future от push. Route обеспечивает полную изоляцию: черновики на детальном экране не влияют на состояние списка.

Часто задаваемые вопросы

В чём разница между Route и Widget в Flutter?

Route — это объект, управляющий экраном на уровне навигации: он хранит анимацию, ModalBarrier и жизненный цикл. Widget — это описание части интерфейса. Route содержит Widget внутри себя, но также предоставляет сервисы (Overlay-слой, Hero-анимация), недоступные обычным виджетам. Один Route может содержать сложную иерархию виджетов любой глубины.

Как создать Route с кастомной анимацией?

Используйте PageRouteBuilder с параметрами pageBuilder (построение экрана) и transitionsBuilder (определение анимации). В transitionsBuilder доступны animation (0.0–1.0) и secondaryAnimation для параллельных анимаций. Для полного контроля создайте подкласс Route и переопределите buildPage, createAnimationController и buildTransitions, что даст доступ к низкоуровневым AnimationController.

Как передать сложный объект между Route?

Для передачи сложных объектов используйте конструктор целевого экрана при прямом Navigator.push или аргумент arguments при pushNamed. Убедитесь, что объект сериализуем (Map, JSON или кастомный класс). Для типобезопасной передачи во Flutter используются freezed или json_serializable модели, которые гарантируют корректную десериализацию при передаче через RouteSettings.

Почему Route может не вызвать dispose?

Route.dispose не вызывается, если Route остаётся в стеке Navigator. Например, при открытии нового Route старый Route переходит в неактивное состояние (Inactive), но не уничтожается — он остаётся в стеке для быстрого возврата. Dispose вызывается только при удалении Route из стека через pop, pushReplacement или pushAndRemoveUntil. Для освобождения ресурсов используйте dispose State внутри Route, а не dispose самого Route.

Как проверить, какой Route сейчас активен?

Используйте ModalRoute.of(context) для получения текущего Route из BuildContext. Свойство ModalRoute.isActive показывает, является ли Route текущим видимым экраном. ModalRoute.isCurrent — true, если Route является вершиной стека. Для наблюдения за изменениями стека подпишитесь на Navigator наблюдателей через RouteAware и RouteObserver, которые уведомляют о смене активного Route.

Итоги

  • Route — абстрактный класс экрана во Flutter с жизненным циклом (didPush, didPop, didReplace, didChangeNext) и поддержкой ModalBarrier и Hero-анимации
  • MaterialPageRoute — реализация для Android с анимацией слайда снизу, тенью и автоматической SafeArea
  • CupertinoPageRoute — реализация для iOS с анимацией слайда справа и интерактивным свайп-назад жестом
  • PageRouteBuilder — утилита для создания Route с кастомной анимацией через transitionsBuilder и AnimationController
  • Передача данных — через конструктор Route (push) или arguments (pushNamed) на вход; через Navigator.pop(context, result) на выход с Future
  • Жизненный цикл — четыре стадии: Transition (didPush), Active, Inactive (перекрыт другим Route), Disposed (didPop + dispose)
  • Изоляция экранов — каждый Route имеет собственный BuildContext и состояние, что предотвращает утечки и упрощает управление данными

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также