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
// Кастомний Route з анімацією слайда
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),
));

// Повернути дані з екрана
ElevatedButton(
  onPressed: () => Navigator.of(context).pop({'selected': true, 'id': '42'}),
  child: const Text('Вибрати'),
);

// Отримати результат на викликаючому екрані
final result = await Navigator.push(context, MaterialPageRoute(
  builder: (context) => const SelectionPage(),
));
if (result != null) {
  print('Вибрано: ${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 переходить у неактивний стан, але не знищується — він залишається в стеку для швидкого повернення. 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 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

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