Le widget Navigator dans Flutter
Le widget Navigator dans Flutter
-
Objectif
- Dans cet article, nous allons implémenter une logique de navigation entre les pages afin que vous puissiez guider vos utilisateurs vers l’objectif.
-
Qu’est-ce que l’API Navigator 2.0 ?
- Au début, la navigation entre les écrans dans Flutter se faisait de manière impérative, en utilisant push, pop, et les amis de Navigator 1.0 et c’était parfaitement bien pour la plupart des applications mobiles.
- C’est l’une des raisons pour lesquelles nous continuons à faire les choses de cette façon, puisque nous n’utilisons pas Flutter pour développer des applications Web.
- L’API Navigator 2.0 est une mise à jour de l’API de navigation dans Flutter qui apporte de nouvelles fonctionnalités et améliore les performances. Cette mise à jour se concentre sur la simplification du code et la facilitation de la création de comportements de navigation personnalisés.
- Les principales améliorations de l’API Navigator 2.0 comprennent:
- La possibilité de définir des chemins de navigation nommés dans le code, ce qui facilite la navigation entre les pages.
- La possibilité de spécifier des transitions personnalisées pour les animations de navigation.
- Une gestion plus flexible des erreurs pour les erreurs de navigation.
- Un système de gestion de la mémoire optimisé pour les applications à grande échelle.
- L’API Navigator 2.0 est une mise à jour importante de l’API de navigation dans Flutter et offre de nouvelles possibilités pour la création d’applications plus performantes et plus flexibles
-
Comment fonctionne Navigator 2.0 ?
- Navigator 2.0 propose une nouvelle conception d’API déclarative, pour le widget Pages existant . Navigator Il introduit également un nouveau widget Router.
- L’API déclarative nouvellement ajoutée de Navigator 2.0 comprend principalement l’ API de page et l’API de routeur . Leurs fonctions puissantes respectives fournissent une base solide pour Navigator 2.0.
- Navigator 2.0 se compose de deux API :
- API des pages
- API de routeur
-
API des pages dans Flutter
- Page API est une nouvelle API déclarative dans les widgets du navigateur. Il définit les itinéraires et les pages qui sont utilisés dans l’application.
- L’API déclarative introduit la classe Page. En tant que développeurs, notre responsabilité est de fournir une liste d’objets Page au widget Navigator dans une discipline de pile. Ensuite, le widget Navigator convertit les objets Page en objets Route. Semblable à la classe Route, la classe Page n’est pas non plus un widget mais une classe qui étend la classe RouteSettings.
- Le widget Navigateur a deux nouveaux arguments passés dans son constructeur :
- pages(Classe de page) : Il s’agit d’une liste de pages où chaque page décrit essentiellement la configuration d’une Route .
- onPopPage: Une fonction de rappel pour l’ impératif pop.
-
Classe de pages
NavigatorState
dans Flutter est un type d’objet qui permet d’accéder au état du widget. Il est utilisé pour gérer la pile de pages dans l’application et peut être utilisé pour push ou pop de pages de la pile.-
Exemple d’utilisation
- Définissez une clé globale pour
NavigatorState
et utilisez-la lors de la création du navigateur. - Utilisez la clé globale ci-dessus dans le constructeur Navigator et fournissez la liste des pages ainsi que les routes de l’application dans la classe de page.
-
onPopPage
- Chaque fois que vous utilisez le Page API, vous devez fournir ce rappel afin de gérer l’impératif popsur la route basée sur la page (route créée par Page API) et selon le résultat que nous obtenons après avoir appelé router.didPop(), nous pouvons mettre à jour la page.
-
API de Routeurs dans Flutter
-
Utiliser
RouterDelegate
RouterDelegate
est un widget de base utilisé par Router. Il répond à l’intention du moteur pour la poussée de route et le pop de route. La nouvelle navigation permet la création deRouterDelegate
pour un meilleur contrôle de la navigation.- Le
RouterDelegate
est une classe de base dans Flutter pour implémenter un comportement de route personnalisé. - Il est utilisé pour définir comment la navigation se produit entre les pages dans une application Flutter. Il peut être utilisé avec un Router pour implémenter un comportement de navigation personnalisé pour l’application.
- Pour utiliser
RouterDelegate
, vous devez implémenter les méthodes suivantes: - build: retourne le widget à afficher pour la page actuelle.
- popRoute: appelé lorsque la page actuelle doit être fermée.
- pushRoute: appelé lorsqu’une nouvelle page doit être ouverte.
-
Applications
-
App01
- Créer une application Flutter basique à deux ou trois pages utilisant l’API Navigator 2.0:
- Dans cet exemple, nous définissons les chemins de navigation nommés dans le MaterialApp en utilisant la propriété routes.
- Lorsque l’utilisateur clique sur le bouton « la première page« , la méthode Navigator.pushNamed est appelée pour naviguer vers la seconde page.
- Lorsque l’utilisateur clique sur le bouton « la seconde page« , la méthode Navigator.pop est appelée pour retourner à la première page.
-
App02
- Il est demandé de réaliser une application Flutter, composée de trois écrans, sur chaque écran, deux boutons sont placés. Ils permettent de se diriger vers une des deux autres pages. Il est intéressant de constater l’effet de pile grâce à l’AppBar. Passé le premier écran, l’AppBar dispose d’une flèche de retour en arrière qui permet de remonter la pile comme le ferait la méthode pop de Navigator.
- L’image suivant décrit les trois pages à réaliser
.
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
Navigator(
key: navigatorKey,
pages: <Page<void>>[
MaterialPage(key: ValueKey('home'), child: MyHomePage()),
if (_myRoute == MyRoute.gallery)
MaterialPage(key: ValueKey('gallery'), child: GalleryPage(_tab)),
if (_myRoute == MyRoute.seeAll)
MaterialPage(key: ValueKey('seeAll'), child: MyLinkPage()),
if (_myRoute == MyRoute.more)
MaterialPage(key: ValueKey('seeAll/more'), child: ContentDetail()),
],
onPopPage: _handlePopPage,
)
Exemple avec deux pages
Solution
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Navigator 2.0 Example',
initialRoute: '/',
routes: {
'/': (context) => FirstPage(),
'/second': (context) => SecondPage(),
},
);
}
}
class FirstPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('La première page'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, '/second');
},
child: const Text('Aller à la deuxième page'),
),
),
);
}
}
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('La deuxième page'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text('Retour'),
),
),
);
}
}
Exemple avec trois pages
Solution
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: '/',
routes: {
'/': (context) => FirstPage(),
'/second': (context) => SecondPage(),
'/third': (context) => ThirdPage(),
},
);
}
}
class FirstPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Première page'),
),
body: Center(
child: ElevatedButton(
child: const Text('Aller à la deuxième page'),
onPressed: () {
Navigator.pushNamed(context, '/second');
},
),
),
);
}
}
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Deuxième page'),
),
body: Center(
child: ElevatedButton(
child: const Text('Aller à la troisième page'),
onPressed: () {
Navigator.pushNamed(context, '/third');
},
),
),
);
}
}
class ThirdPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Troisème page'),
),
body: Center(
child: ElevatedButton(
child: const Text('Retour'),
onPressed: () {
Navigator.pop(context);
},
),
),
);
}
}
Page main.dart
Solution
import 'package:flutter/material.dart';
import 'MyFirstPage.dart';
import 'MySecondPage.dart';
import 'MyThirdPage.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyFirstPage(title: 'Flutter Demo Home Page'),
routes: {
'/route1': (BuildContext context) => MyFirstPage(title: 'Page 1'),
'/route2': (BuildContext context) => MySecondPage(title: 'Page 2'),
'/route3': (BuildContext context) => MyThirdPage(title: 'Page 3'),
},
);
}
}
Page premierePage.dart
Solution
import 'package:flutter/material.dart';
class MyFirstPage extends StatelessWidget {
MyFirstPage({required this.title});
final String title;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
backgroundColor: Colors.green,
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
"Ecran n°1",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 40,
color: Colors.green),
),
const Padding(padding: EdgeInsets.only(bottom: 20)),
const Text("Appuer sur un bouton pour passer à un autre écran"),
const Padding(padding: EdgeInsets.only(bottom: 20)),
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.purple,
padding: const EdgeInsets.symmetric(
horizontal: 50, vertical: 20),
textStyle: const TextStyle(
fontSize: 30, fontWeight: FontWeight.bold)),
onPressed: () {
Navigator.pushNamed(context, '/route2');
},
child: const Text('Ecran n°2')),
const SizedBox(
height: 10,
),
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.purple,
padding: const EdgeInsets.symmetric(
horizontal: 50, vertical: 20),
textStyle: const TextStyle(
fontSize: 30, fontWeight: FontWeight.bold)),
onPressed: () {
Navigator.pushNamed(context, '/route3');
},
child: const Text('Ecran n°3')),
],
),
),
backgroundColor: Colors.green[100],
);
}
}
Page deusiemePage.dart
Solution
import 'package:flutter/material.dart';
class MySecondPage extends StatelessWidget {
MySecondPage({required this.title});
final String title;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
backgroundColor: Colors.teal,
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
"Ecran n°2",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 40,
color: Colors.teal),
),
const Padding(padding: EdgeInsets.only(bottom: 20)),
const Text("Appuer sur ce bouton pour passer à l'écran suivant"),
const Padding(padding: EdgeInsets.only(bottom: 20)),
ElevatedButton(
child: Text('Ecran n°1'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.purple,
padding: const EdgeInsets.symmetric(
horizontal: 50, vertical: 20),
textStyle: const TextStyle(
fontSize: 30, fontWeight: FontWeight.bold)),
onPressed: () {
Navigator.pushNamed(context, '/route1');
}),
SizedBox(height: 10,),
ElevatedButton(
child: Text('Ecran n°3'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.purple,
padding: const EdgeInsets.symmetric(
horizontal: 50, vertical: 20),
textStyle: const TextStyle(
fontSize: 30, fontWeight: FontWeight.bold)),
onPressed: () {
Navigator.pushNamed(context, '/route3');
}),
],
),
),
backgroundColor: Colors.teal[100],
);
}
}
Page troisiemePage.dart
Solution
import 'package:flutter/material.dart';
class MyThirdPage extends StatelessWidget {
MyThirdPage({required this.title});
final String title;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
backgroundColor: Colors.blue,
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Ecran n°3",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 40,
color: Colors.blue),
),
Padding(padding: EdgeInsets.only(bottom: 20)),
Text("Appuer sur ce bouton pour passer à l'écran suivant"),
Padding(padding: EdgeInsets.only(bottom: 20)),
ElevatedButton(
child: Text('Ecran n°1'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.purple,
padding: const EdgeInsets.symmetric(
horizontal: 50, vertical: 20),
textStyle: const TextStyle(
fontSize: 30, fontWeight: FontWeight.bold)),
onPressed: () {
Navigator.pushNamed(context, '/route1');
}),
SizedBox(
height: 10,
),
ElevatedButton(
child: Text('Ecran n°2'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.purple,
padding: const EdgeInsets.symmetric(
horizontal: 50, vertical: 20),
textStyle: const TextStyle(
fontSize: 30, fontWeight: FontWeight.bold)),
onPressed: () {
Navigator.pushNamed(context, '/route2');
}),
],
),
),
backgroundColor: Colors.blue[100],
);
}
}