Route — este o clasă abstractă în Flutter care reprezintă un ecran sau o pagină separată în istoricul de navigare Navigator. Implementările concrete ale Route — MaterialPageRoute, CupertinoPageRoute și PlatformRoute — determină cum este afișat ecranul și ce animație este folosită la tranziție. Spre deosebire de un widget obișnuit, Route are propriul ciclu de viață cu metodele didPush, didPop, didReplace și didChangeNext. Conform Flutter API Reference (2026), fiecare Route gestionează ModalBarrier, ține cont de particularitățile platformei (glisarea înapoi pe iOS) și asigură izolarea stării între ecrane.
Principalele puncte
Route — este baza sistemului de navigare Flutter. Fiecare ecran pe care utilizatorul îl vede în aplicație este reprezentat de un obiect Route aflat în stiva Navigator. Route abstrage ecranul de codul de gestionare: Navigator adaugă și elimină Route, iar în interiorul Route se află interfața pe care o vede utilizatorul. Această arhitectură separă responsabilitatea între navigare și afișare.
Spre deosebire de simpla înlocuire a widgeturilor, Route oferă servicii indisponibile widgeturilor obișnuite: ModalBarrier (întunecarea fundalului la deschiderea unui dialog), gestionarea animației de intrare și ieșire, procesarea butonului hardware „Înapoi” pe Android și integrarea cu animația Hero pentru tranziții fluide între ecrane.
Conform Flutter Cookbook (2026), Route este un element cheie pentru animația Hero: widgetul Hero pe un Route animează automat tranziția către widgetul Hero pe următorul Route, creând efectul unui element „zburător”. Acest lucru este posibil tocmai pentru că Route păstrează ambele ecrane în Overlay în timpul animației.
Route este fundamentul atât pentru aplicațiile mobile simple (prin Navigator 1.0), cât și pentru scenarii complexe cu linkuri adânci (Navigator 2.0). În Navigator 2.0, Route reprezintă un Page pe care RouterDelegate îl convertește din configurația rutei. Astfel, înțelegerea Route este necesară pentru lucrul cu orice sistem de navigare Flutter — indiferent de abordarea sau pachetul ales.
Flutter oferă mai multe implementări încorporate ale Route, fiecare adaptând comportamentul pentru o platformă specifică. Alegerea tipului corect de Route influențează experiența utilizatorului: animația Material pe Android și animația Cupertino pe iOS creează senzația unei aplicații „native”.
| Tip Route | Animație | Platformă | Caracteristici |
|---|---|---|---|
| MaterialPageRoute | Derulare de jos în sus | Android, desktop | umbră la tranziție, gestionare automată SafeArea |
| CupertinoPageRoute | Derulare din dreapta la stânga | iOS, iPadOS | gest de glisare înapoi, fundal transparent la tranziție |
| PlatformRoute | Selectare automată | Toate platformele | selectează tipul pe baza TargetPlatform |
| PageRouteBuilder | Personalizată | Toate platformele | control complet asupra animației prin AnimationController |
MaterialPageRoute — cea mai frecvent utilizată implementare Route. Animează intrarea unui nou ecran de jos în sus cu apariție treptată. La ieșire, ecranul se animează de sus în jos, revenind la poziția inițială. Bara de instrumente (AppBar) și corpul ecranului se animează separat, creând un efect de ierarhie.
CupertinoPageRoute imită UINavigationController din iOS. Noul ecran intră din dreapta, acoperindu-l pe cel anterior. Caracteristica cheie — suportul pentru gestul interactiv de glisare înapoi, implementat prin CupertinoBackGestureDetector. Acest gest este procesat chiar și în mijlocul animației, asigurând un comportament natural familiar utilizatorilor iPhone.
Route are propriul ciclu de viață care diferă de ciclul de viață al unui StatefulWidget obișnuit. Înțelegerea acestui ciclu este necesară pentru inițializarea corectă a datelor, abonarea la streamuri și eliberarea resurselor la închiderea ecranului.
Ciclul de viață al Route constă din patru etape principale. Transition — Route este creat și animat la intrare (se apelează didPush). Active — Route este afișat complet și interacționează cu utilizatorul. Inactive — un alt Route acoperă cel curent (dialog, ecran inferior), dar Route rămâne în stivă. Disposed — Route este eliminat din stivă și distrus, se apelează didPop și dispose.
Metodele ciclului de viață ale Route pot fi suprascrise într-o implementare personalizată. De exemplu, didPop este apelat când Route este eliminat din stivă — aici se poate salva o ciornă de date. didChangeNext este apelat când următorul Route din stivă s-a schimbat — util pentru actualizarea UI la modificarea istoricului de navigare.
Conform Flutter API Route.didPop (2026), este important să nu confundăm ciclul de viață al Route cu ciclul de viață al State-ului din interiorul Route. StatefulWidget din interiorul Route are propriile initState și dispose care sunt apelate în etapele Transition și, respectiv, Disposed. Route trăiește mai mult decât State-ul său intern — Route rămâne în Overlay chiar și atunci când widgeturile sale sunt temporar ascunse de un alt Route.
Route oferă mecanisme pentru transmiterea datelor atât la intrare (la creare), cât și la ieșire (la finalizare). Transmiterea corectă a datelor prin Route elimină necesitatea variabilelor globale și a InheritedWidget, făcând navigarea tip-sigură și predictibilă.
Pentru transmiterea datelor către un nou ecran se folosește constructorul widgetului destinatar sau argumentul arguments în Navigator.pushNamed. În interiorul Route, datele sunt accesibile prin RouteSettings.arguments care este stocat în obiectul Route. Această abordare funcționează pentru toate tipurile de Route — MaterialPageRoute, CupertinoPageRoute și implementări personalizate.
Pentru returnarea datelor se folosește al doilea argument Navigator.pop(context, result). Navigator.push returnează un Future
La apelul direct Navigator.push cu MaterialPageRoute, datele sunt transmise prin constructorul ecranului țintă. MethodChannel nu este folosit — este o interacțiune pură Dart. Această abordare este preferată pentru transmiterea tip-sigură a obiectelor complexe.
Să examinăm un exemplu de creare a unui Route personalizat cu animație proprie și transmitere de date. PageRouteBuilder permite definirea animației de intrare și ieșire cu control complet asupra curbei de animație și duratei.
// Route personalizat cu animație de derulare
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),
));
// Returnează datele din ecran
ElevatedButton(
onPressed: () => Navigator.of(context).pop({'selected': true, 'id': '42'}),
child: const Text('Selectează'),
);
// Obține rezultatul pe ecranul apelant
final result = await Navigator.push(context, MaterialPageRoute(
builder: (context) => const SelectionPage(),
));
if (result != null) {
print('Selectat: ${result['selected']}');
}
În exemplu, PageRouteBuilder definește o animație personalizată de derulare de jos cu transparență. transitionDuration stabilește viteza animației. Codul demonstrează și transmiterea rezultatului: ecranul de detalii returnează un Map cu alegerea utilizatorului, iar ecranul apelant primește aceste date prin Future de la push. Route asigură izolarea completă: ciornele de pe ecranul de detalii nu afectează starea listei.
Întrebări frecvente
Route — este un obiect care gestionează ecranul la nivel de navigare: stochează animația, ModalBarrier și ciclul de viață. Widget — este descrierea unei părți de interfață. Route conține Widget în interiorul său, dar oferă și servicii (stratul Overlay, animația Hero) indisponibile widgeturilor obișnuite. Un singur Route poate conține o ierarhie complexă de widgeturi de orice adâncime.
Folosiți PageRouteBuilder cu parametrii pageBuilder (construirea ecranului) și transitionsBuilder (definirea animației). În transitionsBuilder sunt disponibile animation (0.0–1.0) și secondaryAnimation pentru animații paralele. Pentru control total, creați o subclasă a Route și suprascrieți buildPage, createAnimationController și buildTransitions, ceea ce va oferi acces la AnimationController de nivel scăzut.
Pentru transmiterea obiectelor complexe, folosiți constructorul ecranului țintă la Navigator.push direct sau argumentul arguments la pushNamed. Asigurați-vă că obiectul este serializabil (Map, JSON sau clasă personalizată). Pentru transmiterea tip-sigură în Flutter se folosesc modele freezed sau json_serializable care garantează deserializarea corectă la transmiterea prin RouteSettings.
Route.dispose nu este apelat dacă Route rămâne în stiva Navigator. De exemplu, la deschiderea unui nou Route, vechiul Route trece în stare inactivă (Inactive), dar nu este distrus — rămâne în stivă pentru revenire rapidă. Dispose este apelat doar la eliminarea Route din stivă prin pop, pushReplacement sau pushAndRemoveUntil. Pentru eliberarea resurselor, folosiți dispose al State-ului din interiorul Route, nu dispose al Route-ului însuși.
Folosiți ModalRoute.of(context) pentru a obține Route-ul curent din BuildContext. Proprietatea ModalRoute.isActive arată dacă Route este ecranul vizibil curent. ModalRoute.isCurrent — true dacă Route este în vârful stivei. Pentru observarea modificărilor stivei, abonați-vă la observatorii Navigator prin RouteAware și RouteObserver, care notifică despre schimbarea Route-ului activ.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și