Route est une classe abstraite dans Flutter qui représente un écran ou une page individuelle dans l'historique de navigation du Navigator. Les implémentations concrètes de Route — MaterialPageRoute, CupertinoPageRoute et PlatformRoute — déterminent comment l'écran est affiché et quelle animation est utilisée lors de la transition. Contrairement à un widget ordinaire, Route a son propre cycle de vie avec les méthodes didPush, didPop, didReplace et didChangeNext. Selon la Flutter API Reference (2026), chaque Route gère ModalBarrier, prend en compte les caractéristiques spécifiques à la plateforme (balayer en arrière sur iOS) et assure l'isolation d'état entre les écrans.
Points clés
Route est le fondement du système de navigation Flutter. Chaque écran que l'utilisateur voit dans une application est représenté par un objet Route situé dans la pile du Navigator. Route abstrait l'écran du code de contrôle : Navigator ajoute et supprime Route, tandis qu'à l'intérieur de Route se trouve l'interface que l'utilisateur voit. Cette architecture sépare la responsabilité entre la navigation et l'affichage.
Contrairement au simple remplacement de widgets, Route fournit des services indisponibles pour les widgets ordinaires : ModalBarrier (assombrissement de l'arrière-plan lorsqu'une boîte de dialogue est ouverte), contrôle de l'animation d'entrée et de sortie, gestion du bouton de retour matériel sur Android et intégration avec l'animation Hero pour des transitions fluides entre les écrans.
Selon Flutter Cookbook (2026), Route est un élément clé pour l'animation Hero : un widget Hero sur une Route anime automatiquement la transition vers un widget Hero sur la Route suivante, créant un effet d'élément « volant ». Ceci est possible précisément parce que Route maintient les deux écrans dans l'Overlay pendant l'animation.
Route est la base à la fois pour les applications mobiles simples (via Navigator 1.0) et pour les scénarios complexes avec liens profonds (Navigator 2.0). Dans Navigator 2.0, Route représente une Page que RouterDelegate convertit à partir de la configuration de route. Ainsi, comprendre Route est essentiel pour travailler avec tout système de navigation Flutter — indépendamment de l'approche ou du paquet choisi.
Flutter fournit plusieurs implémentations intégrées de Route, chacune adaptant le comportement à une plateforme spécifique. Choisir le bon type de Route affecte l'expérience utilisateur : l'animation Material sur Android et l'animation Cupertino sur iOS créent la sensation d'une application « native ».
| Type de Route | Animation | Plateforme | Caractéristiques |
|---|---|---|---|
| MaterialPageRoute | Glissement de bas en haut | Android, bureau | Ombre lors de la transition, gestion automatique de SafeArea |
| CupertinoPageRoute | Glissement de droite à gauche | iOS, iPadOS | Geste de balayage arrière, fond transparent pendant la transition |
| PlatformRoute | Sélection automatique | Toutes les plateformes | Sélectionne le type basé sur TargetPlatform |
| PageRouteBuilder | Personnalisée | Toutes les plateformes | Contrôle total sur l'animation via AnimationController |
MaterialPageRoute est l'implémentation de Route la plus utilisée. Elle anime le nouvel écran entrant de bas en haut avec une apparition graduelle. En sortant, l'écran s'anime de haut en bas, retournant à sa position d'origine. La barre d'outils (AppBar) et le corps de l'écran s'animent séparément, créant un effet de hiérarchie.
CupertinoPageRoute imite UINavigationController d'iOS. Le nouvel écran entre par la droite, couvrant le précédent. La caractéristique clé est le support du geste interactif de balayage arrière, implémenté via CupertinoBackGestureDetector. Ce geste est géré même pendant l'animation, offrant un comportement naturel familier aux utilisateurs d'iPhone.
Route a son propre cycle de vie, qui diffère du cycle de vie d'un StatefulWidget ordinaire. Comprendre ce cycle est nécessaire pour l'initialisation correcte des données, les abonnements aux flux et la libération des ressources lors de la fermeture d'un écran.
Le cycle de vie de Route comprend quatre étapes principales. Transition — Route est créée et animée à l'entrée (didPush est appelé). Actif — Route est entièrement affichée et interagit avec l'utilisateur. Inactif — une autre Route couvre la Route actuelle (dialogue, feuille inférieure), mais la Route reste dans la pile. Détruit — Route est retirée de la pile et détruite, didPop et dispose sont appelés.
Les méthodes du cycle de vie de Route peuvent être surchargées dans une implémentation personnalisée. Par exemple, didPop est appelé lorsque Route est retirée de la pile — ici vous pouvez sauvegarder des données de brouillon. didChangeNext est appelé lorsque la Route suivante dans la pile a changé — utile pour mettre à jour l'UI lorsque l'historique de navigation change.
Selon Flutter API Route.didPop (2026), il est important de ne pas confondre le cycle de vie de Route avec le cycle de vie de State à l'intérieur de Route. StatefulWidget à l'intérieur de Route a son propre initState et dispose, qui sont appelés respectivement pendant les étapes de Transition et Détruit. Route vit plus longtemps que son State interne — Route reste dans l'Overlay même lorsque ses widgets sont temporairement cachés par une autre Route.
Route fournit des mécanismes pour passer des données à la fois à l'entrée (lors de la création) et à la sortie (à la fin). Le passage correct de données via Route élimine le besoin de variables globales et d'InheritedWidget, rendant la navigation type-safe et prévisible.
Pour passer des données à un nouvel écran, utilisez le constructeur du widget récepteur ou le paramètre arguments dans Navigator.pushNamed. À l'intérieur de Route, les données sont accessibles via RouteSettings.arguments, qui est stocké dans l'objet Route. Cette approche fonctionne pour tous les types de Route — MaterialPageRoute, CupertinoPageRoute et les implémentations personnalisées.
Pour retourner des données, utilisez le deuxième argument de Navigator.pop(context, result). Navigator.push retourne Future
Lors de l'appel direct à Navigator.push avec MaterialPageRoute, les données sont passées via le constructeur de l'écran cible. MethodChannel n'est pas utilisé — c'est une interaction Dart pure. Cette approche est préférable pour le passage type-safe d'objets complexes.
Regardons un exemple de création d'une Route personnalisée avec sa propre animation et passage de données. PageRouteBuilder permet de définir des animations d'entrée et de sortie avec un contrôle total sur la courbe d'animation et la durée.
// Route personnalisée avec animation de glissement
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),
));
// Retourner les données de l'écran
ElevatedButton(
onPressed: () => Navigator.of(context).pop({'selected': true, 'id': '42'}),
child: const Text('Sélectionner'),
);
// Obtenir le résultat sur l'écran appelant
final result = await Navigator.push(context, MaterialPageRoute(
builder: (context) => const SelectionPage(),
));
if (result != null) {
print('Sélectionné : ${result['selected']}');
}
Dans l'exemple, PageRouteBuilder définit une animation personnalisée de glissement depuis le bas avec transparence. transitionDuration définit la vitesse de l'animation. Le code démontre également le passage de résultat : l'écran de détail retourne un Map avec la sélection de l'utilisateur, et l'écran appelant reçoit ces données via le Future de push. Route garantit une isolation complète : les brouillons sur l'écran de détail n'affectent pas l'état de la liste.
Questions fréquentes
Route est un objet qui gère un écran au niveau de la navigation : il stocke l'animation, ModalBarrier et le cycle de vie. Widget est une description d'une partie de l'interface. Route contient Widget à l'intérieur de lui-même, mais fournit également des services (couche Overlay, animation Hero) indisponibles pour les widgets ordinaires. Une Route peut contenir une hiérarchie complexe de widgets de n'importe quelle profondeur.
Utilisez PageRouteBuilder avec les paramètres pageBuilder (construction de l'écran) et transitionsBuilder (définition de l'animation). Dans transitionsBuilder, animation (0.0–1.0) et secondaryAnimation sont disponibles pour les animations parallèles. Pour un contrôle total, créez une sous-classe de Route et surchargez buildPage, createAnimationController et buildTransitions, donnant accès à AnimationController de bas niveau.
Pour passer des objets complexes, utilisez le constructeur de l'écran cible lors de l'appel direct à Navigator.push ou le paramètre arguments avec pushNamed. Assurez-vous que l'objet est sérialisable (Map, JSON ou classe personnalisée). Pour un passage type-safe dans Flutter, utilisez des modèles freezed ou json_serializable, qui garantissent une désérialisation correcte lors du passage via RouteSettings.
Route.dispose n'est pas appelé si Route reste dans la pile du Navigator. Par exemple, lors de l'ouverture d'une nouvelle Route, l'ancienne Route passe en état inactif mais n'est pas détruite — elle reste dans la pile pour un retour rapide. Dispose est appelé uniquement lorsque Route est retirée de la pile via pop, pushReplacement ou pushAndRemoveUntil. Pour libérer des ressources, utilisez le dispose de State à l'intérieur de Route, pas le dispose de Route elle-même.
Utilisez ModalRoute.of(context) pour obtenir la Route actuelle depuis BuildContext. La propriété ModalRoute.isActive montre si la Route est l'écran actuellement visible. ModalRoute.isCurrent — true si la Route est le sommet de la pile. Pour observer les changements de pile, abonnez-vous aux observateurs du Navigator via RouteAware et RouteObserver, qui notifient des changements de Route active.
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi