Navigation Hub
Introduction
Navigation Hubs are a central place where you can manage the navigation for all your widgets. Out the box you can create bottom, top and journey navigation layouts in seconds.
Let's imagine you have an app and you want to add a bottom navigation bar and allow users to navigate between different tabs in your app.
You can use a Navigation Hub to build this.
Let's dive into how you can use a Navigation Hub in your app.
Basic Usage
You can create a Navigation Hub using the below command.
dart run nylo_framework:main make:navigation_hub base
// or with Metro
metro make:navigation_hub base
This will create a base_navigation_hub.dart file in your resources/pages/ directory.
import 'package:flutter/material.dart';
import 'package:nylo_framework/nylo_framework.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> {
/// Layouts:
/// - [NavigationHubLayout.bottomNav] Bottom navigation
/// - [NavigationHubLayout.topNav] Top navigation
/// - [NavigationHubLayout.journey] Journey navigation
NavigationHubLayout? layout = NavigationHubLayout.bottomNav(
// backgroundColor: Colors.white,
);
/// Should the state be maintained
@override
bool get maintainState => true;
/// Navigation pages
_BaseNavigationHubState() : super(() async {
return {
0: NavigationTab(
title: "Home",
page: HomeTab(),
icon: Icon(Icons.home),
activeIcon: Icon(Icons.home),
),
1: NavigationTab(
title: "Settings",
page: SettingsTab(),
icon: Icon(Icons.settings),
activeIcon: Icon(Icons.settings),
),
};
});
}
You can see that the Navigation Hub has two tabs, Home and Settings.
You can create more tabs by adding NavigationTab's to the Navigation Hub.
First, you need to create a new widget using Metro.
dart run nylo_framework:main make:stateful_widget create_advert_tab
// or with Metro
metro make:stateful_widget create_advert_tab
You can also create multiple widgets at once.
dart run nylo_framework:main make:stateful_widget news_tab,notifications_tab
// or with Metro
metro make:stateful_widget news_tab,notifications_tab
Then, you can add the new widget to the Navigation Hub.
_BaseNavigationHubState() : super(() async {
return {
0: NavigationTab(
title: "Home",
page: HomeTab(),
icon: Icon(Icons.home),
activeIcon: Icon(Icons.home),
),
1: NavigationTab(
title: "Settings",
page: SettingsTab(),
icon: Icon(Icons.settings),
activeIcon: Icon(Icons.settings),
),
2: NavigationTab(
title: "News",
page: NewsTab(),
icon: Icon(Icons.newspaper),
activeIcon: Icon(Icons.newspaper),
),
};
});
import 'package:nylo_framework/nylo_framework.dart';
appRouter() => nyRoutes((router) {
...
router.add(BaseNavigationHub.path).initalRoute();
});
// or navigate to the Navigation Hub from anywhere in your app
routeTo(BaseNavigationHub.path);
There's a lot more you can do with a Navigation Hub, let's dive into some of the features.
Bottom Navigation
You can change the layout to a bottom navigation bar by setting the layout to use NavigationHubLayout.bottomNav.
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
...
NavigationHubLayout? layout = NavigationHubLayout.bottomNav();
You can customize the bottom navigation bar by setting properties like the following:
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
...
NavigationHubLayout? layout = NavigationHubLayout.bottomNav(
// customize the bottomNav layout properties
);
Top Navigation
You can change the layout to a top navigation bar by setting the layout to use NavigationHubLayout.topNav.
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
...
NavigationHubLayout? layout = NavigationHubLayout.topNav();
You can customize the top navigation bar by setting properties like the following:
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
...
NavigationHubLayout? layout = NavigationHubLayout.topNav(
// customize the topNav layout properties
);
Journey Navigation
You can change the layout to a journey navigation by setting the layout to use NavigationHubLayout.journey.
This is great for onboarding flows or multi-step forms.
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
...
NavigationHubLayout? layout = NavigationHubLayout.journey(
// customize the journey layout properties
);
If you want to use the journey navigation layout, your widgets should use JourenyState as it contains a lot of helper methods to help you manage the journey.
You can create a JourneyState using the below command.
dart run nylo_framework:main make:journey_widget welcome,phone_number_step,add_photos_step
// or with Metro
metro make:journey_widget welcome,phone_number_step,add_photos_step
This will create the following files in your resources/widgets/ directory welcome.dart, phone_number_step.dart and add_photos_step.dart.
You can then add the new widgets to the Navigation Hub.
_MyNavigationHubState() : super(() async {
return {
0: NavigationTab.journey(
page: Welcome(),
),
1: NavigationTab.journey(
page: PhoneNumberStep(),
),
2: NavigationTab.journey(
page: AddPhotosStep(),
),
};
});
The journey navigation layout will automatically handle the back and next buttons for you if you define a buttonStyle.
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
...
NavigationHubLayout? layout = NavigationHubLayout.journey(
buttonStyle: JourneyButtonStyle.standard(
// Customize button properties
),
);
You can also customize the logic in your widgets.
import 'package:flutter/material.dart';
import '/resources/pages/onboarding_navigation_hub.dart';
import '/resources/widgets/buttons/buttons.dart';
import 'package:nylo_framework/nylo_framework.dart';
class WelcomeStep extends StatefulWidget {
const WelcomeStep({super.key});
@override
createState() => _WelcomeStepState();
}
class _WelcomeStepState extends JourneyState<WelcomeStep> {
_WelcomeStepState() : super(
navigationHubState: OnboardingNavigationHub.path.stateName());
@override
get init => () {
// Your initialization logic here
};
@override
Widget view(BuildContext context) {
return buildJourneyContent(
content: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('WelcomeStep', 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: onNextPressed,
),
backButton: isFirstStep ? null : Button.textOnly(
text: "Back",
textColor: Colors.black87,
onPressed: onBackPressed,
),
);
}
/// Check if the journey can continue to the next step
/// Override this method to add validation logic
Future<bool> canContinue() async {
// Perform your validation logic here
// Return true if the journey can continue, false otherwise
return true;
}
/// Called when unable to continue (canContinue returns false)
/// Override this method to handle validation failures
Future<void> onCannotContinue() async {
showToastSorry(description: "You cannot continue");
}
/// Called before navigating to the next step
/// Override this method to perform actions before continuing
Future<void> onBeforeNext() async {
// E.g. save data here before navigating
}
/// Called after navigating to the next step
/// Override this method to perform actions after continuing
Future<void> onAfterNext() async {
// print('Navigated to the next step');
}
/// Called when the journey is complete (at the last step)
/// Override this method to perform completion actions
Future<void> onComplete() async {}
}
You can override any of the methods in the JourneyState class.
Journey Progress Styles
You can customize the progress indicator style by using the JourneyProgressStyle class.
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
...
NavigationHubLayout? layout = NavigationHubLayout.journey(
progressStyle: JourneyProgressStyle.linear(
activeColor: Colors.blue,
inactiveColor: Colors.grey,
thickness: 4.0,
),
);
You can use the following progress styles:
JourneyProgressStyle.linear: Linear progress indicator.JourneyProgressStyle.dots: Dots-based progress indicator.JourneyProgressStyle.numbered: Numbered step progress indicator.JourneyProgressStyle.segments: Segmented progress bar style.JourneyProgressStyle.circular: Circular progress indicator.JourneyProgressStyle.timeline: Timeline-style progress indicator.JourneyProgressStyle.custom: Custom progress indicator using a builder function.
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
...
NavigationHubLayout? layout = NavigationHubLayout.journey(
progressStyle: JourneyProgressStyle.custom(
builder: (context, currentStep, totalSteps, percentage) {
return LinearProgressIndicator(
value: percentage,
backgroundColor: Colors.grey[200],
color: Colors.blue,
minHeight: 4.0,
);
},
),
);
You can also customize the progress indicator position by using the progressIndicatorPosition property.
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
...
NavigationHubLayout? layout = NavigationHubLayout.journey(
progressIndicatorPosition: ProgressIndicatorPosition.top,
);
You can use the following progress indicator positions:
ProgressIndicatorPosition.top: Progress indicator at the top of the screen.ProgressIndicatorPosition.bottom: Progress indicator at the bottom of the screen.
You can also customize the progress indicator padding by using the progressIndicatorPadding property.
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
...
NavigationHubLayout? layout = NavigationHubLayout.journey(
progressIndicatorPadding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
);