Route — co to jest, typy i tworzenie marszrut we Flutter

Autor: IT Sectr Opublikowano: 2026-07-02 Czas czytania: 8 min

Route — to abstrakcyjna klasa we Flutter, reprezentująca osobny ekran lub stronę w historii nawigacji Navigator. Konkretne implementacje Route — MaterialPageRoute, CupertinoPageRoute i PlatformRoute — określają, jak ekran jest wyświetlany i jaka animacja jest używana przy przejściu. W przeciwieństwie do zwykłego widgetu, Route ma własny cykl życia z metodami didPush, didPop, didReplace i didChangeNext. Według Flutter API Reference (2026), każdy Route zarządza ModalBarrier, uwzględnia cechy platformy (przesunięcie wstecz na iOS) i zapewnia izolację stanu między ekranami.

Najważniejsze

  • Route — abstrakcyjna klasa ekranu we Flutter z własnym cyklem życia (didPush, didPop, didReplace, didChangeNext)
  • MaterialPageRoute — standardowa implementacja Route z animacją Material (przesunięcie z dołu) dla Androida i desktopu
  • CupertinoPageRoute — implementacja Route z animacją iOS (przesunięcie z prawej + gest przesunięcia wstecz) dla iPhone i iPad
  • Cykl życia — Route przechodzi etapy: przejście (Transition), wyświetlenie (Active), ukrycie (Inactive) i zniszczenie (Disposed)
  • Przekazywanie danych — Route przyjmuje argumenty przez konstruktor i zwraca wynik przez Future po zakończeniu

Czym jest Route we Flutter

Route — to podstawa systemu nawigacji Flutter. Każdy ekran, który użytkownik widzi w aplikacji, jest reprezentowany przez obiekt Route znajdujący się w stosie Navigator. Route abstrahuje ekran od kodu zarządzającego: Navigator dodaje i usuwa Route, a wewnątrz Route znajduje się interfejs widoczny dla użytkownika. Taka architektura rozdziela odpowiedzialność między nawigacją a wyświetlaniem.

W przeciwieństwie do zwykłej zamiany widgetów, Route zapewnia usługi niedostępne dla zwykłych widgetów: ModalBarrier (przyciemnienie tła przy otwartym oknie dialogowym), zarządzanie animacją wejścia i wyjścia, obsługę sprzętowego przycisku „Wstecz” na Androidzie oraz integrację z animacją Hero dla płynnych przejść między ekranami.

Według Flutter Cookbook (2026), Route jest kluczowym elementem animacji Hero: widget Hero na jednym Route automatycznie animuje przejście do widgetu Hero na następnym Route, tworząc efekt „lecącego” elementu. Jest to możliwe właśnie dlatego, że Route przechowuje oba ekrany w Overlay podczas animacji.

Route jako budulec nawigacji

Route jest podstawą zarówno dla prostych aplikacji mobilnych (przez Navigator 1.0), jak i dla złożonych scenariuszy z głębokimi linkami (Navigator 2.0). W Navigator 2.0 Route reprezentuje Page, który RouterDelegate konwertuje z konfiguracji marszruty. Zatem zrozumienie Route jest niezbędne do pracy z dowolnym systemem nawigacji Flutter — niezależnie od wybranego podejścia lub pakietu.

Typy Route: MaterialPageRoute i CupertinoPageRoute

Flutter udostępnia kilka wbudowanych implementacji Route, z których każda dostosowuje zachowanie do konkretnej platformy. Wybór odpowiedniego typu Route wpływa na doświadczenie użytkownika: animacja Material na Androidzie i animacja Cupertino na iOS tworzą wrażenie „natywnej” aplikacji.

Typ RouteAnimacjaPlatformaCechy
MaterialPageRoutePrzesunięcie z dołu do góryAndroid, desktopcień przy przejściu, automatyczna obsługa SafeArea
CupertinoPageRoutePrzesunięcie z prawej do lewejiOS, iPadOSgest przesunięcia wstecz, przezroczyste tło przy przejściu
PlatformRouteAutomatyczny wybórWszystkie platformywybiera typ na podstawie TargetPlatform
PageRouteBuilderNiestandardowaWszystkie platformypełna kontrola nad animacją przez AnimationController

MaterialPageRoute: standard dla Androida

MaterialPageRoute — to najczęściej używana implementacja Route. Animuje wejście nowego ekranu od dołu do góry ze stopniowym pojawianiem się. Przy wyjściu ekran animuje się z góry na dół, wracając do pozycji początkowej. Panel narzędzi (AppBar) i treść ekranu animują się osobno, tworząc efekt hierarchii.

CupertinoPageRoute: styl nawigacji iOS

CupertinoPageRoute imituje UINavigationController z iOS. Nowy ekran wjeżdża z prawej strony, zakrywając poprzedni. Kluczową cechą jest obsługa interaktywnego gestu przesunięcia wstecz, zaimplementowana przez CupertinoBackGestureDetector. Ten gest jest obsługiwany nawet w środku animacji, zapewniając naturalne zachowanie znane użytkownikom iPhone.

Cykl życia Route: od utworzenia do zniszczenia

Route ma własny cykl życia, który różni się od cyklu życia zwykłego StatefulWidget. Zrozumienie tego cyklu jest niezbędne do prawidłowej inicjalizacji danych, subskrypcji strumieni i zwalniania zasobów przy zamykaniu ekranu.

Etapy cyklu życia Route

Cykl życia Route składa się z czterech głównych etapów. Transition — Route jest tworzony i animowany przy wejściu (wywołuje didPush). Active — Route jest w pełni wyświetlany i interaktywny dla użytkownika. Inactive — inny Route zasłania bieżący (dialog, dolny ekran), ale Route pozostaje w stosie. Disposed — Route jest usuwany ze stosu i niszczony, wywoływane są didPop i dispose.

Metody cyklu życia Route mogą być nadpisane w niestandardowej implementacji. Na przykład didPop jest wywoływany, gdy Route jest usuwany ze stosu — tutaj można zapisać wersję roboczą danych. didChangeNext jest wywoływany, gdy następny Route w stosie się zmienił — przydatne do aktualizacji UI przy zmianie historii nawigacji.

Według Flutter API Route.didPop (2026), ważne jest, aby nie mylić cyklu życia Route z cyklem życia State wewnątrz Route. StatefulWidget wewnątrz Route ma własne initState i dispose, które są wywoływane odpowiednio na etapach Transition i Disposed. Route żyje dłużej niż jego wewnętrzny State — Route pozostaje w Overlay nawet gdy jego widgety są tymczasowo ukryte przez inny Route.

Przekazywanie danych przez Route między ekranami

Route zapewnia mechanizmy do przesyłania danych zarówno na wejściu (przy tworzeniu), jak i na wyjściu (przy zakończeniu). Prawidłowe przesyłanie danych przez Route eliminuje potrzebę globalnych zmiennych i InheritedWidget, czyniąc nawigację bezpieczną typowo i przewidywalną.

Do przesyłania danych na nowy ekran używany jest konstruktor odbierającego widgetu lub argument arguments w Navigator.pushNamed. Wewnątrz Route dane są dostępne przez RouteSettings.arguments, który jest przechowywany w obiekcie Route. To podejście działa dla wszystkich typów Route — MaterialPageRoute, CupertinoPageRoute i niestandardowych implementacji.

Do zwracania danych używany jest drugi argument Navigator.pop(context, result). Navigator.push zwraca Future, który kończy się wartością przekazaną w pop. Jeśli pop jest wywołany bez argumentu, Future kończy się z null. Ten mechanizm to odpowiednik startActivityForResult w Androidzie i completion handler w iOS, ale zaimplementowany przez Dart Futures.

Przykład przesyłania danych przez konstruktor Route

Przy bezpośrednim wywołaniu Navigator.push z MaterialPageRoute dane są przesyłane przez konstruktor docelowego ekranu. MethodChannel nie jest używany — to czysta interakcja Dart. Takie podejście jest preferowane do typowo bezpiecznego przesyłania złożonych obiektów.

Przykład tworzenia niestandardowego Route

Rozważmy przykład tworzenia niestandardowego Route z własną animacją i przesyłaniem danych. PageRouteBuilder pozwala zdefiniować animację wejścia i wyjścia z pełną kontrolą nad krzywą animacji i czasem trwania.

dart
// Niestandardowy Route z animacją przesunięcia
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),
));

// Zwróć dane z ekranu
ElevatedButton(
  onPressed: () => Navigator.of(context).pop({'selected': true, 'id': '42'}),
  child: const Text('Wybierz'),
);

// Pobierz wynik na ekranie wywołującym
final result = await Navigator.push(context, MaterialPageRoute(
  builder: (context) => const SelectionPage(),
));
if (result != null) {
  print('Wybrano: ${result['selected']}');
}

W przykładzie PageRouteBuilder definiuje niestandardową animację przesunięcia z dołu z przezroczystością. transitionDuration określa prędkość animacji. Kod demonstruje również przesyłanie wyniku: ekran szczegółów zwraca Map z wyborem użytkownika, a ekran wywołujący otrzymuje te dane przez Future z push. Route zapewnia pełną izolację: wersje robocze na ekranie szczegółów nie wpływają na stan listy.

Często zadawane pytania

Jaka jest różnica między Route a Widget we Flutter?

Route — to obiekt zarządzający ekranem na poziomie nawigacji: przechowuje animację, ModalBarrier i cykl życia. Widget — to opis części interfejsu. Route zawiera Widget wewnątrz siebie, ale także zapewnia usługi (warstwa Overlay, animacja Hero) niedostępne dla zwykłych widgetów. Jeden Route może zawierać złożoną hierarchię widgetów o dowolnej głębokości.

Jak utworzyć Route z niestandardową animacją?

Użyj PageRouteBuilder z parametrami pageBuilder (budowa ekranu) i transitionsBuilder (definicja animacji). W transitionsBuilder dostępne są animation (0.0–1.0) i secondaryAnimation dla równoległych animacji. Dla pełnej kontroli utwórz podklasę Route i nadpisz buildPage, createAnimationController i buildTransitions, co da dostęp do niskopoziomowych AnimationController.

Jak przesłać złożony obiekt między Route?

Do przesyłania złożonych obiektów użyj konstruktora docelowego ekranu przy bezpośrednim Navigator.push lub argumentu arguments przy pushNamed. Upewnij się, że obiekt jest serializowalny (Map, JSON lub niestandardowa klasa). Do typowo bezpiecznego przesyłania we Flutter używane są modele freezed lub json_serializable, które gwarantują poprawną deserializację przy przesyłaniu przez RouteSettings.

Dlaczego Route może nie wywołać dispose?

Route.dispose nie jest wywoływane, jeśli Route pozostaje w stosie Navigator. Na przykład przy otwieraniu nowego Route stary Route przechodzi w stan nieaktywny (Inactive), ale nie jest niszczony — pozostaje w stosie do szybkiego powrotu. Dispose jest wywoływane tylko przy usunięciu Route ze stosu przez pop, pushReplacement lub pushAndRemoveUntil. Do zwalniania zasobów używaj dispose State wewnątrz Route, a nie dispose samego Route.

Jak sprawdzić, który Route jest teraz aktywny?

Użyj ModalRoute.of(context) do pobrania bieżącego Route z BuildContext. Właściwość ModalRoute.isActive pokazuje, czy Route jest aktualnie widocznym ekranem. ModalRoute.isCurrent — true, jeśli Route jest na szczycie stosu. Do obserwowania zmian stosu subskrybuj obserwatorów Navigator przez RouteAware i RouteObserver, które powiadamiają o zmianie aktywnego Route.

Podsumowanie

  • Route — abstrakcyjna klasa ekranu we Flutter z cyklem życia (didPush, didPop, didReplace, didChangeNext) i obsługą ModalBarrier i animacji Hero
  • MaterialPageRoute — implementacja dla Androida z animacją przesunięcia z dołu, cieniem i automatycznym SafeArea
  • CupertinoPageRoute — implementacja dla iOS z animacją przesunięcia z prawej i interaktywnym gestem przesunięcia wstecz
  • PageRouteBuilder — narzędzie do tworzenia Route z niestandardową animacją przez transitionsBuilder i AnimationController
  • Przekazywanie danych — przez konstruktor Route (push) lub arguments (pushNamed) na wejściu; przez Navigator.pop(context, result) na wyjściu z Future
  • Cykl życia — cztery etapy: Transition (didPush), Active, Inactive (zasłonięty przez inny Route), Disposed (didPop + dispose)
  • Izolacja ekranów — każdy Route ma własny BuildContext i stan, co zapobiega wyciekom i upraszcza zarządzanie danymi

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również