Route — какво е, типове и създаване на маршрути в Flutter

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

Route — е абстрактен клас в Flutter, който представлява отделен екран или страница в навигационната история на Navigator. Конкретните имплементации на Route — MaterialPageRoute, CupertinoPageRoute и PlatformRoute — определят как се показва екранът и каква анимация се използва при прехода. За разлика от обикновения widget, 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 се намира интерфейсът, който потребителят вижда. Такава архитектура разделя отговорността между навигацията и показването.

За разлика от обикновената смяна на widgets, Route предоставя услуги, недостъпни за обикновените widgets: ModalBarrier (затъмняване на фона при отворен диалог), управление на анимация за влизане и излизане, обработка на хардуерния бутон „Назад“ на Android и интеграция с Hero анимация за плавни преходи между екрани.

Според Flutter Cookbook (2026), Route е ключов елемент за Hero анимация: Hero widget на един Route автоматично анимира прехода към Hero widget на следващия 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 дори когато неговите widgets са временно скрити от друг Route.

Прехвърляне на данни чрез Route между екрани

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

За прехвърляне на данни към нов екран се използва конструкторът на приемащия widget или аргументът 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 анимация), недостъпни за обикновените widgets. Един Route може да съдържа сложна йерархия от widgets с произволна дълбочина.

Как да създам 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 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също