Navigation Hub
Introduction
Les Navigation Hubs sont un endroit central où vous pouvez gérer la navigation de tous vos widgets. Par défaut, vous pouvez créer des mises en page de navigation inférieure, supérieure et journey en quelques secondes.
Imaginons que vous avez une application et que vous souhaitez ajouter une barre de navigation inférieure permettant aux utilisateurs de naviguer entre différents onglets.
Vous pouvez utiliser un Navigation Hub pour construire cela.
Voyons comment utiliser un Navigation Hub dans votre application.
Utilisation de base
Vous pouvez créer un Navigation Hub en utilisant la commande ci-dessous.
metro make:navigation_hub base
La commande vous guidera à travers une configuration interactive :
- Choisir un type de mise en page - Sélectionnez entre
navigation_tabs(navigation inférieure) oujourney_states(flux séquentiel). - Saisir les noms des tabs/states - Fournissez des noms séparés par des virgules pour vos tabs ou journey states.
Cela créera des fichiers dans votre répertoire resources/pages/navigation_hubs/base/ :
base_navigation_hub.dart- Le widget principal du hubtabs/oustates/- Contient les widgets enfants pour chaque tab ou journey state
Voici à quoi ressemble un Navigation Hub généré :
import 'package:flutter/material.dart';
import 'package:nylo_framework/nylo_framework.dart';
import '/resources/pages/navigation_hubs/base/tabs/home_tab_widget.dart';
import '/resources/pages/navigation_hubs/base/tabs/settings_tab_widget.dart';
class BaseNavigationHub extends NyStatefulWidget with BottomNavPageControls {
static RouteView path = ("/base", (_) => BaseNavigationHub());
BaseNavigationHub()
: super(
child: () => _BaseNavigationHubState(),
stateName: path.stateName());
/// State actions
static NavigationHubStateActions stateActions = NavigationHubStateActions(path.stateName());
}
class _BaseNavigationHubState extends NavigationHub<BaseNavigationHub> {
/// Layout builder
@override
NavigationHubLayout? layout(BuildContext context) => NavigationHubLayout.bottomNav();
/// Should the state be maintained
@override
bool get maintainState => true;
/// The initial index
@override
int get initialIndex => 0;
/// Navigation pages
_BaseNavigationHubState() : super(() => {
0: NavigationTab.tab(title: "Home", page: HomeTab()),
1: NavigationTab.tab(title: "Settings", page: SettingsTab()),
});
/// Handle the tap event
@override
onTap(int index) {
super.onTap(index);
}
}
Vous pouvez voir que le Navigation Hub possède deux onglets, Home et Settings.
La méthode layout retourne le type de mise en page du hub. Elle reçoit un BuildContext qui vous permet d'accéder aux données du thème et aux media queries lors de la configuration de votre mise en page.
Vous pouvez créer davantage d'onglets en ajoutant des NavigationTab au Navigation Hub.
Tout d'abord, vous devez créer un nouveau widget en utilisant Metro.
metro make:stateful_widget news_tab
Vous pouvez également créer plusieurs widgets en une seule fois.
metro make:stateful_widget news_tab,notifications_tab
Ensuite, vous pouvez ajouter le nouveau widget au Navigation Hub.
_BaseNavigationHubState() : super(() => {
0: NavigationTab.tab(title: "Home", page: HomeTab()),
1: NavigationTab.tab(title: "Settings", page: SettingsTab()),
2: NavigationTab.tab(title: "News", page: NewsTab()),
});
Pour utiliser le Navigation Hub, ajoutez-le à votre routeur comme route initiale :
import 'package:nylo_framework/nylo_framework.dart';
appRouter() => nyRoutes((router) {
...
router.add(BaseNavigationHub.path).initialRoute();
});
// or navigate to the Navigation Hub from anywhere in your app
routeTo(BaseNavigationHub.path);
Il y a beaucoup plus de choses que vous pouvez faire avec un Navigation Hub. Explorons certaines de ses fonctionnalités.
Navigation inférieure
Vous pouvez définir la mise en page sur une barre de navigation inférieure en retournant NavigationHubLayout.bottomNav depuis la méthode layout.
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
...
@override
NavigationHubLayout? layout(BuildContext context) => NavigationHubLayout.bottomNav();
Vous pouvez personnaliser la barre de navigation inférieure en définissant des propriétés comme celles-ci :
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
...
@override
NavigationHubLayout? layout(BuildContext context) => NavigationHubLayout.bottomNav(
backgroundColor: Colors.white,
selectedItemColor: Colors.blue,
unselectedItemColor: Colors.grey,
elevation: 8.0,
iconSize: 24.0,
selectedFontSize: 14.0,
unselectedFontSize: 12.0,
showSelectedLabels: true,
showUnselectedLabels: true,
type: BottomNavigationBarType.fixed,
);
Vous pouvez appliquer un style prédéfini à votre barre de navigation inférieure en utilisant le paramètre style.
@override
NavigationHubLayout? layout(BuildContext context) => NavigationHubLayout.bottomNav(
style: BottomNavStyle.material(), // Default Flutter material style
);
Constructeur de barre de navigation personnalisé
Pour un contrôle total sur votre barre de navigation, vous pouvez utiliser le paramètre navBarBuilder.
Cela vous permet de construire n'importe quel widget personnalisé tout en recevant les données de navigation.
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
...
@override
NavigationHubLayout? layout(BuildContext context) => NavigationHubLayout.bottomNav(
navBarBuilder: (context, data) {
return MyCustomNavBar(
items: data.items,
currentIndex: data.currentIndex,
onTap: data.onTap,
);
},
);
L'objet NavBarData contient :
| Propriété | Type | Description |
|---|---|---|
items |
List<BottomNavigationBarItem> |
Les éléments de la barre de navigation |
currentIndex |
int |
L'index actuellement sélectionné |
onTap |
ValueChanged<int> |
Callback lorsqu'un onglet est touché |
Voici un exemple de barre de navigation glass entièrement personnalisée :
NavigationHubLayout.bottomNav(
navBarBuilder: (context, data) {
return Padding(
padding: EdgeInsets.all(16),
child: ClipRRect(
borderRadius: BorderRadius.circular(25),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
child: Container(
decoration: BoxDecoration(
color: Colors.white.withValues(alpha: 0.7),
borderRadius: BorderRadius.circular(25),
),
child: BottomNavigationBar(
items: data.items,
currentIndex: data.currentIndex,
onTap: data.onTap,
backgroundColor: Colors.transparent,
elevation: 0,
),
),
),
),
);
},
)
Note : Lorsque vous utilisez
navBarBuilder, le paramètrestyleest ignoré.
Navigation supérieure
Vous pouvez changer la mise en page pour une barre de navigation supérieure en retournant NavigationHubLayout.topNav depuis la méthode layout.
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
...
@override
NavigationHubLayout? layout(BuildContext context) => NavigationHubLayout.topNav();
Vous pouvez personnaliser la barre de navigation supérieure en définissant des propriétés comme celles-ci :
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
...
@override
NavigationHubLayout? layout(BuildContext context) => NavigationHubLayout.topNav(
backgroundColor: Colors.white,
labelColor: Colors.blue,
unselectedLabelColor: Colors.grey,
indicatorColor: Colors.blue,
indicatorWeight: 3.0,
isScrollable: false,
hideAppBarTitle: true,
);
Navigation journey
Vous pouvez changer la mise en page pour une navigation journey en retournant NavigationHubLayout.journey depuis la méthode layout.
C'est idéal pour les flux d'onboarding ou les formulaires multi-étapes.
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
...
@override
NavigationHubLayout? layout(BuildContext context) => NavigationHubLayout.journey(
progressStyle: JourneyProgressStyle(
indicator: JourneyProgressIndicator.segments(),
),
);
Vous pouvez également définir un backgroundGradient pour la mise en page journey :
@override
NavigationHubLayout? layout(BuildContext context) => NavigationHubLayout.journey(
backgroundGradient: LinearGradient(
colors: [Colors.blue, Colors.purple],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
progressStyle: JourneyProgressStyle(
indicator: JourneyProgressIndicator.linear(),
),
);
Note : Lorsque
backgroundGradientest défini, il a priorité surbackgroundColor.
Si vous souhaitez utiliser la mise en page de navigation journey, vos widgets devraient utiliser JourneyState car il contient de nombreuses méthodes d'aide pour gérer le parcours.
Vous pouvez créer l'ensemble du journey en utilisant la commande make:navigation_hub avec la mise en page journey_states :
metro make:navigation_hub onboarding
# Select: journey_states
# Enter: welcome, personal_info, add_photos
Cela créera le hub ainsi que tous les widgets de journey state dans resources/pages/navigation_hubs/onboarding/states/.
Vous pouvez également créer des widgets journey individuels en utilisant :
metro make:journey_widget welcome,phone_number_step,add_photos_step
Vous pouvez ensuite ajouter les nouveaux widgets au Navigation Hub.
_MyNavigationHubState() : super(() => {
0: NavigationTab.journey(
page: Welcome(),
),
1: NavigationTab.journey(
page: PhoneNumberStep(),
),
2: NavigationTab.journey(
page: AddPhotosStep(),
),
});
Styles de progression journey
Vous pouvez personnaliser le style de l'indicateur de progression en utilisant la classe JourneyProgressStyle.
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
...
@override
NavigationHubLayout? layout(BuildContext context) => NavigationHubLayout.journey(
progressStyle: JourneyProgressStyle(
indicator: JourneyProgressIndicator.linear(
activeColor: Colors.blue,
inactiveColor: Colors.grey,
thickness: 4.0,
),
),
);
Vous pouvez utiliser les indicateurs de progression suivants :
JourneyProgressIndicator.none(): Ne rend rien -- utile pour masquer l'indicateur sur un onglet spécifique.JourneyProgressIndicator.linear(): Barre de progression linéaire.JourneyProgressIndicator.dots(): Indicateur de progression à points.JourneyProgressIndicator.numbered(): Indicateur de progression avec étapes numérotées.JourneyProgressIndicator.segments(): Style de barre de progression segmentée.JourneyProgressIndicator.circular(): Indicateur de progression circulaire.JourneyProgressIndicator.timeline(): Indicateur de progression en style timeline.JourneyProgressIndicator.custom(): Indicateur de progression personnalisé utilisant une fonction builder.
@override
NavigationHubLayout? layout(BuildContext context) => NavigationHubLayout.journey(
progressStyle: JourneyProgressStyle(
indicator: JourneyProgressIndicator.custom(
builder: (context, currentStep, totalSteps, percentage) {
return LinearProgressIndicator(
value: percentage,
backgroundColor: Colors.grey[200],
color: Colors.blue,
minHeight: 4.0,
);
},
),
),
);
Vous pouvez personnaliser la position et le padding de l'indicateur de progression dans le JourneyProgressStyle :
@override
NavigationHubLayout? layout(BuildContext context) => NavigationHubLayout.journey(
progressStyle: JourneyProgressStyle(
indicator: JourneyProgressIndicator.dots(),
position: ProgressIndicatorPosition.bottom,
padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
),
);
Vous pouvez utiliser les positions d'indicateur de progression suivantes :
ProgressIndicatorPosition.top: Indicateur de progression en haut de l'écran.ProgressIndicatorPosition.bottom: Indicateur de progression en bas de l'écran.
Remplacement du style de progression par onglet
Vous pouvez remplacer le progressStyle au niveau du layout sur des onglets individuels en utilisant NavigationTab.journey(progressStyle: ...). Les onglets sans leur propre progressStyle héritent du style par défaut du layout. Les onglets sans style par défaut du layout et sans style par onglet n'afficheront pas d'indicateur de progression.
_MyNavigationHubState() : super(() => {
0: NavigationTab.journey(
page: Welcome(),
),
1: NavigationTab.journey(
page: PhoneNumberStep(),
progressStyle: JourneyProgressStyle(
indicator: JourneyProgressIndicator.numbered(),
), // overrides the layout default for this tab only
),
2: NavigationTab.journey(
page: AddPhotosStep(),
),
});
JourneyState
La classe JourneyState étend NyState avec des fonctionnalités spécifiques au journey pour faciliter la création de flux d'onboarding et de parcours multi-étapes.
Pour créer un nouveau JourneyState, vous pouvez utiliser la commande ci-dessous.
metro make:journey_widget onboard_user_dob
Ou si vous souhaitez créer plusieurs widgets en une seule fois, vous pouvez utiliser la commande suivante.
metro make:journey_widget welcome,phone_number_step,add_photos_step
Voici à quoi ressemble un widget JourneyState généré :
import 'package:flutter/material.dart';
import '/resources/pages/navigation_hubs/onboarding/onboarding_navigation_hub.dart';
import '/resources/widgets/buttons/buttons.dart';
import 'package:nylo_framework/nylo_framework.dart';
class Welcome extends StatefulWidget {
const Welcome({super.key});
@override
createState() => _WelcomeState();
}
class _WelcomeState extends JourneyState<Welcome> {
_WelcomeState() : super(
navigationHubState: OnboardingNavigationHub.path.stateName());
@override
get init => () {
// Your initialization logic here
};
@override
Widget view(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
Expanded(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Welcome', style: Theme.of(context).textTheme.headlineMedium),
const SizedBox(height: 20),
Text('This onboarding journey will help you get started.'),
],
),
),
),
// Navigation buttons
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
if (!isFirstStep)
Flexible(
child: Button.textOnly(
text: "Back",
textColor: Colors.black87,
onPressed: onBackPressed,
),
)
else
const SizedBox.shrink(),
Flexible(
child: Button.primary(
text: "Continue",
onPressed: nextStep,
),
),
],
),
],
),
);
}
/// Check if the journey can continue to the next step
@override
Future<bool> canContinue() async {
return true;
}
/// Called before navigating to the next step
@override
Future<void> onBeforeNext() async {
// E.g. save data to session
}
/// Called when the journey is complete (at the last step)
@override
Future<void> onComplete() async {}
}
Vous remarquerez que la classe JourneyState utilise nextStep pour avancer et onBackPressed pour revenir en arrière.
La méthode nextStep exécute l'ensemble du cycle de vie de validation : canContinue() -> onBeforeNext() -> navigation (ou onComplete() si c'est la dernière étape) -> onAfterNext().
Vous pouvez également utiliser buildJourneyContent pour construire une mise en page structurée avec des boutons de navigation optionnels :
@override
Widget view(BuildContext context) {
return buildJourneyContent(
content: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Welcome', style: Theme.of(context).textTheme.headlineMedium),
const SizedBox(height: 20),
Text('This onboarding journey will help you get started.'),
],
),
nextButton: Button.primary(
text: isLastStep ? "Get Started" : "Continue",
onPressed: nextStep,
),
backButton: isFirstStep ? null : Button.textOnly(
text: "Back",
textColor: Colors.black87,
onPressed: onBackPressed,
),
);
}
Voici les propriétés que vous pouvez utiliser dans la méthode buildJourneyContent.
| Propriété | Type | Description |
|---|---|---|
content |
Widget |
Le contenu principal de la page. |
nextButton |
Widget? |
Le widget du bouton suivant. |
backButton |
Widget? |
Le widget du bouton retour. |
contentPadding |
EdgeInsetsGeometry |
Le padding du contenu. |
header |
Widget? |
Le widget d'en-tête. |
footer |
Widget? |
Le widget de pied de page. |
crossAxisAlignment |
CrossAxisAlignment |
L'alignement de l'axe transversal du contenu. |
Méthodes d'aide JourneyState
La classe JourneyState possède des méthodes et propriétés d'aide que vous pouvez utiliser pour personnaliser le comportement de votre parcours.
| Méthode / Propriété | Description |
|---|---|
nextStep() |
Navigue vers l'étape suivante avec validation. Retourne Future<bool>. |
previousStep() |
Navigue vers l'étape précédente. Retourne Future<bool>. |
onBackPressed() |
Helper simple pour naviguer vers l'étape précédente. |
onComplete() |
Appelée lorsque le parcours est terminé (à la dernière étape). |
onBeforeNext() |
Appelée avant la navigation vers l'étape suivante. |
onAfterNext() |
Appelée après la navigation vers l'étape suivante. |
canContinue() |
Vérification de validation avant la navigation vers l'étape suivante. |
isFirstStep |
Retourne true si c'est la première étape du parcours. |
isLastStep |
Retourne true si c'est la dernière étape du parcours. |
currentStep |
Retourne l'index de l'étape actuelle (base 0). |
totalSteps |
Retourne le nombre total d'étapes. |
completionPercentage |
Retourne le pourcentage de complétion (0.0 à 1.0). |
goToStep(int index) |
Sauter directement à une étape spécifique par index. |
goToNextStep() |
Sauter à l'étape suivante (sans validation). |
goToPreviousStep() |
Sauter à l'étape précédente (sans validation). |
goToFirstStep() |
Sauter à la première étape. |
goToLastStep() |
Sauter à la dernière étape. |
exitJourney() |
Quitter le journey en faisant un pop du navigateur racine. |
resetCurrentStep() |
Réinitialiser l'état de l'étape actuelle. |
onJourneyComplete |
Callback lorsque le journey est terminé (à surcharger dans la dernière étape). |
buildJourneyPage() |
Construire une page journey plein écran avec Scaffold. |
nextStep
La méthode nextStep navigue vers l'étape suivante avec une validation complète. Elle exécute le cycle de vie : canContinue() -> onBeforeNext() -> navigation ou onComplete() -> onAfterNext().
Vous pouvez passer force: true pour contourner la validation et naviguer directement.
@override
Widget view(BuildContext context) {
return buildJourneyContent(
content: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
...
],
),
nextButton: Button.primary(
text: isLastStep ? "Get Started" : "Continue",
onPressed: nextStep, // runs validation then navigates
),
);
}
Pour ignorer la validation :
onPressed: () => nextStep(force: true),
previousStep
La méthode previousStep navigue vers l'étape précédente. Retourne true en cas de succès, false si vous êtes déjà à la première étape.
onPressed: () async {
bool success = await previousStep();
if (!success) {
// Already at first step
}
},
onBackPressed
La méthode onBackPressed est un helper simple qui appelle previousStep() en interne.
@override
Widget view(BuildContext context) {
return buildJourneyContent(
content: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
...
],
),
backButton: isFirstStep ? null : Button.textOnly(
text: "Back",
textColor: Colors.black87,
onPressed: onBackPressed,
),
);
}
onComplete
La méthode onComplete est appelée lorsque nextStep() est déclenché à la dernière étape (après que la validation est passée).
@override
Future<void> onComplete() async {
print("Journey completed");
}
onBeforeNext
La méthode onBeforeNext est appelée avant la navigation vers l'étape suivante.
Par exemple, si vous souhaitez sauvegarder des données avant de naviguer vers l'étape suivante, vous pouvez le faire ici.
@override
Future<void> onBeforeNext() async {
// E.g. save data to session
// session('onboarding', {
// 'name': 'Anthony Gordon',
// 'occupation': 'Software Engineer',
// });
}
onAfterNext
La méthode onAfterNext est appelée après la navigation vers l'étape suivante.
@override
Future<void> onAfterNext() async {
// print('Navigated to the next step');
}
canContinue
La méthode canContinue est appelée lorsque nextStep() est déclenché. Retournez false pour empêcher la navigation.
@override
Future<bool> canContinue() async {
// Perform your validation logic here
// Return true if the journey can continue, false otherwise
if (nameController.text.isEmpty) {
showToastSorry(description: "Please enter your name");
return false;
}
return true;
}
isFirstStep
La propriété isFirstStep retourne true si c'est la première étape du parcours.
backButton: isFirstStep ? null : Button.textOnly(
text: "Back",
textColor: Colors.black87,
onPressed: onBackPressed,
),
isLastStep
La propriété isLastStep retourne true si c'est la dernière étape du parcours.
nextButton: Button.primary(
text: isLastStep ? "Get Started" : "Continue",
onPressed: nextStep,
),
currentStep
La propriété currentStep retourne l'index de l'étape actuelle (base 0).
Text("Step ${currentStep + 1} of $totalSteps"),
totalSteps
La propriété totalSteps retourne le nombre total d'étapes du parcours.
completionPercentage
La propriété completionPercentage retourne le pourcentage de complétion sous forme de valeur allant de 0.0 à 1.0.
LinearProgressIndicator(value: completionPercentage),
goToStep
La méthode goToStep saute directement à une étape spécifique par index. Cela ne déclenche pas de validation.
nextButton: Button.primary(
text: "Skip to photos",
onPressed: () {
goToStep(2); // jump to step index 2
},
),
goToNextStep
La méthode goToNextStep saute à l'étape suivante sans validation. Si vous êtes déjà à la dernière étape, elle ne fait rien.
onPressed: () {
goToNextStep(); // skip validation and go to next step
},
goToPreviousStep
La méthode goToPreviousStep saute à l'étape précédente sans validation. Si vous êtes déjà à la première étape, elle ne fait rien.
onPressed: () {
goToPreviousStep();
},
goToFirstStep
La méthode goToFirstStep saute à la première étape.
onPressed: () {
goToFirstStep();
},
goToLastStep
La méthode goToLastStep saute à la dernière étape.
onPressed: () {
goToLastStep();
},
exitJourney
La méthode exitJourney quitte le journey en faisant un pop du navigateur racine.
onPressed: () {
exitJourney(); // pop the root navigator
},
resetCurrentStep
La méthode resetCurrentStep réinitialise l'état de l'étape actuelle.
onPressed: () {
resetCurrentStep();
},
onJourneyComplete
Le getter onJourneyComplete peut être surchargé dans la dernière étape de votre journey pour définir ce qui se passe lorsque l'utilisateur termine le flux.
class _CompleteStepState extends JourneyState<CompleteStep> {
_CompleteStepState() : super(
navigationHubState: OnboardingNavigationHub.path.stateName());
/// Callback when journey completes
@override
void Function()? get onJourneyComplete => () {
// Navigate to your home page or next destination
routeTo(HomePage.path);
};
@override
Widget view(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
...
Button.primary(
text: "Get Started",
onPressed: onJourneyComplete, // triggers the completion callback
),
],
),
);
}
}
buildJourneyPage
La méthode buildJourneyPage construit une page journey plein écran enveloppée dans un Scaffold avec SafeArea.
@override
Widget view(BuildContext context) {
return buildJourneyPage(
content: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Welcome', style: Theme.of(context).textTheme.headlineMedium),
],
),
nextButton: Button.primary(
text: "Continue",
onPressed: nextStep,
),
backgroundColor: Colors.white,
);
}
| Propriété | Type | Description |
|---|---|---|
content |
Widget |
Le contenu principal de la page. |
nextButton |
Widget? |
Le widget du bouton suivant. |
backButton |
Widget? |
Le widget du bouton retour. |
contentPadding |
EdgeInsetsGeometry |
Le padding du contenu. |
header |
Widget? |
Le widget d'en-tête. |
footer |
Widget? |
Le widget de pied de page. |
backgroundColor |
Color? |
La couleur d'arrière-plan du Scaffold. |
appBar |
Widget? |
Un widget AppBar optionnel. |
crossAxisAlignment |
CrossAxisAlignment |
L'alignement de l'axe transversal du contenu. |
Naviguer vers des widgets au sein d'un onglet
Vous pouvez naviguer vers des widgets au sein d'un onglet en utilisant le helper pushTo.
Dans votre onglet, vous pouvez utiliser le helper pushTo pour naviguer vers un autre widget.
_HomeTabState extends State<HomeTab> {
...
void _navigateToSettings() {
pushTo(SettingsPage());
}
...
}
Vous pouvez également passer des données au widget vers lequel vous naviguez.
_HomeTabState extends State<HomeTab> {
...
void _navigateToSettings() {
pushTo(SettingsPage(), data: {"name": "Anthony"});
}
...
}
Onglets
Les onglets sont les éléments de base d'un Navigation Hub.
Vous pouvez ajouter des onglets à un Navigation Hub en utilisant la classe NavigationTab et ses constructeurs nommés.
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
...
@override
NavigationHubLayout? layout(BuildContext context) => NavigationHubLayout.bottomNav();
...
_MyNavigationHubState() : super(() => {
0: NavigationTab.tab(
title: "Home",
page: HomeTab(),
icon: Icon(Icons.home),
activeIcon: Icon(Icons.home),
),
1: NavigationTab.tab(
title: "Settings",
page: SettingsTab(),
icon: Icon(Icons.settings),
activeIcon: Icon(Icons.settings),
),
});
Dans l'exemple ci-dessus, nous avons ajouté deux onglets au Navigation Hub, Home et Settings.
Vous pouvez utiliser différents types d'onglets :
NavigationTab.tab()- Un onglet de navigation standard.NavigationTab.badge()- Un onglet avec un compteur de badge.NavigationTab.alert()- Un onglet avec un indicateur d'alerte.NavigationTab.journey()- Un onglet pour les mises en page de navigation journey.
Ajouter des badges aux onglets
Nous avons facilité l'ajout de badges à vos onglets.
Les badges sont un excellent moyen de montrer aux utilisateurs qu'il y a quelque chose de nouveau dans un onglet.
Par exemple, si vous avez une application de chat, vous pouvez afficher le nombre de messages non lus dans l'onglet de chat.
Pour ajouter un badge à un onglet, vous pouvez utiliser le constructeur NavigationTab.badge.
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
...
@override
NavigationHubLayout? layout(BuildContext context) => NavigationHubLayout.bottomNav();
...
_MyNavigationHubState() : super(() => {
0: NavigationTab.badge(
title: "Chats",
page: ChatTab(),
icon: Icon(Icons.message),
activeIcon: Icon(Icons.message),
initialCount: 10,
),
1: NavigationTab.tab(
title: "Settings",
page: SettingsTab(),
icon: Icon(Icons.settings),
activeIcon: Icon(Icons.settings),
),
});
Dans l'exemple ci-dessus, nous avons ajouté un badge à l'onglet Chat avec un compteur initial de 10.
Vous pouvez également mettre à jour le compteur du badge par programmation.
/// Increment the badge count
BaseNavigationHub.stateActions.incrementBadgeCount(tab: 0);
/// Update the badge count
BaseNavigationHub.stateActions.updateBadgeCount(tab: 0, count: 5);
/// Clear the badge count
BaseNavigationHub.stateActions.clearBadgeCount(tab: 0);
Par défaut, le compteur du badge sera mémorisé. Si vous souhaitez effacer le compteur du badge à chaque session, vous pouvez définir rememberCount à false.
0: NavigationTab.badge(
title: "Chats",
page: ChatTab(),
icon: Icon(Icons.message),
activeIcon: Icon(Icons.message),
initialCount: 10,
rememberCount: false,
),
Ajouter des alertes aux onglets
Vous pouvez ajouter des alertes à vos onglets.
Parfois, vous ne souhaitez pas afficher un compteur de badge, mais vous voulez montrer un indicateur d'alerte à l'utilisateur.
Pour ajouter une alerte à un onglet, vous pouvez utiliser le constructeur NavigationTab.alert.
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
...
@override
NavigationHubLayout? layout(BuildContext context) => NavigationHubLayout.bottomNav();
...
_MyNavigationHubState() : super(() => {
0: NavigationTab.alert(
title: "Chats",
page: ChatTab(),
icon: Icon(Icons.message),
activeIcon: Icon(Icons.message),
alertColor: Colors.red,
alertEnabled: true,
rememberAlert: false,
),
1: NavigationTab.tab(
title: "Settings",
page: SettingsTab(),
icon: Icon(Icons.settings),
activeIcon: Icon(Icons.settings),
),
});
Cela ajoutera une alerte à l'onglet Chat avec une couleur rouge.
Vous pouvez également mettre à jour l'alerte par programmation.
/// Enable the alert
BaseNavigationHub.stateActions.alertEnableTab(tab: 0);
/// Disable the alert
BaseNavigationHub.stateActions.alertDisableTab(tab: 0);
Index initial
Par défaut, le Navigation Hub démarre sur le premier onglet (index 0). Vous pouvez modifier cela en surchargeant le getter initialIndex.
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
...
@override
int get initialIndex => 1; // Start on the second tab
...
}
Maintien de l'état
Par défaut, l'état du Navigation Hub est maintenu.
Cela signifie que lorsque vous naviguez vers un onglet, l'état de l'onglet est préservé.
Si vous souhaitez effacer l'état de l'onglet à chaque fois que vous y naviguez, vous pouvez définir maintainState à false.
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
...
@override
bool get maintainState => false;
...
}
onTap
Vous pouvez surcharger la méthode onTap pour ajouter une logique personnalisée lorsqu'un onglet est touché.
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
...
@override
onTap(int index) {
// Add custom logic here
// E.g. track analytics, show confirmation, etc.
super.onTap(index); // Always call super to handle the tab switch
}
}
Actions d'état
Les actions d'état sont un moyen d'interagir avec le Navigation Hub depuis n'importe où dans votre application.
Voici les actions d'état que vous pouvez utiliser :
/// Reset the tab at a given index
/// E.g. MyNavigationHub.stateActions.resetTabIndex(0);
resetTabIndex(int tabIndex);
/// Change the current tab programmatically
/// E.g. MyNavigationHub.stateActions.currentTabIndex(2);
currentTabIndex(int tabIndex);
/// Update the badge count
/// E.g. MyNavigationHub.stateActions.updateBadgeCount(tab: 0, count: 2);
updateBadgeCount({required int tab, required int count});
/// Increment the badge count
/// E.g. MyNavigationHub.stateActions.incrementBadgeCount(tab: 0);
incrementBadgeCount({required int tab});
/// Clear the badge count
/// E.g. MyNavigationHub.stateActions.clearBadgeCount(tab: 0);
clearBadgeCount({required int tab});
/// Enable the alert for a tab
/// E.g. MyNavigationHub.stateActions.alertEnableTab(tab: 0);
alertEnableTab({required int tab});
/// Disable the alert for a tab
/// E.g. MyNavigationHub.stateActions.alertDisableTab(tab: 0);
alertDisableTab({required int tab});
/// Navigate to the next page in a journey layout
/// E.g. await MyNavigationHub.stateActions.nextPage();
Future<bool> nextPage();
/// Navigate to the previous page in a journey layout
/// E.g. await MyNavigationHub.stateActions.previousPage();
Future<bool> previousPage();
Pour utiliser une action d'état, vous pouvez faire ce qui suit :
MyNavigationHub.stateActions.updateBadgeCount(tab: 0, count: 2);
MyNavigationHub.stateActions.resetTabIndex(0);
MyNavigationHub.stateActions.currentTabIndex(2); // Switch to tab 2
await MyNavigationHub.stateActions.nextPage(); // Journey: go to next page
Style de chargement
Par défaut, le Navigation Hub affichera votre widget de chargement par défaut (resources/widgets/loader_widget.dart) lorsque l'onglet est en cours de chargement.
Vous pouvez personnaliser le loadingStyle pour modifier le style de chargement.
| Style | Description |
|---|---|
| normal | Style de chargement par défaut |
| skeletonizer | Style de chargement squelette |
| none | Pas de style de chargement |
Vous pouvez changer le style de chargement comme ceci :
@override
LoadingStyle get loadingStyle => LoadingStyle.normal();
// or
@override
LoadingStyle get loadingStyle => LoadingStyle.skeletonizer();
Si vous souhaitez modifier le widget de chargement dans l'un des styles, vous pouvez passer un child au LoadingStyle.
@override
LoadingStyle get loadingStyle => LoadingStyle.normal(
child: Center(
child: Text("Loading..."),
),
);
Désormais, lorsque l'onglet est en cours de chargement, le texte "Loading..." sera affiché.
Exemple ci-dessous :
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
...
_MyNavigationHubState() : super(() async {
await sleep(3); // simulate loading for 3 seconds
return {
0: NavigationTab.tab(
title: "Home",
page: HomeTab(),
),
1: NavigationTab.tab(
title: "Settings",
page: SettingsTab(),
),
};
});
@override
LoadingStyle get loadingStyle => LoadingStyle.normal(
child: Center(
child: Text("Loading..."),
),
);
...
}
Créer un Navigation Hub
Pour créer un Navigation Hub, vous pouvez utiliser Metro, utilisez la commande ci-dessous.
metro make:navigation_hub base
La commande vous guidera à travers une configuration interactive où vous pourrez choisir le type de mise en page et définir vos tabs ou journey states.
Cela créera un fichier base_navigation_hub.dart dans votre répertoire resources/pages/navigation_hubs/base/ avec les widgets enfants organisés dans les sous-dossiers tabs/ ou states/.