In mobile app navigation is important. It dictates how users seamlessly transition between different screens within your Flutter application. In Flutter, you can navigate by pushing the screen on the screen stacks using the built-in Navigator widget and popping the layer on the back button. Apart from that Flutter navigation using routers can be used. Routers make the navigation more streamlined and easy to manage.
What are Routers in Flutter?
Routers act as intermediaries between the Navigator and your app’s screens. They simplify the route management and enhance the code organization. There are many popular route management packages in Flutter.
- go_router (https://pub.dev/packages/go_router)
- fluro (https://pub.dev/packages/fluro)
- provider_router (https://pub.dev/packages/flutter_router)
You are open to trying them, however, with this tutorial, we are going with the default approach for navigation.
Why Use Routers in Flutter navigation?
There are several advantages of using routers. At the initial level, you may not realize of to use this but as the app grows or for a large application such as eCommerce you should use routers.
- Clarity and Organization: Routers create a structured and organised navigation system that helps you to understand and maintain code.
- Deep Linking: Deep linking enables users to enter specific URLs or navigate from external links directly to relevant screens within your app. Flutter navigation using routers can handle deep linking easily.
- Code Reusability: Routers promote code reusability by encapsulating navigation logic in a centralized location, preventing redundancy across your app.
Let’s understand this with an example
To understand this first of all we need to set up a project in Flutter.
1. Project Setup:
Using the following command in your working directory you can create a new flutter project.
flutter create navigation_router_example
2. Define Routes
Open the main.dart file and import the necessary package.
import 'package:navigationrouterexample/view/screens/navigation_router_example.dart';
void main() async {
runApp( NavigationRouterExample()));
}
DartCreate a new file navigation_router_example.dart in the project directory under view/screen folder. You can choose any path that you would like.
import 'package:flutter/material.dart';
import 'package:brahmkshatirya/view/theme/theme.dart' as theme_data;
class NavigationRouterExample extends StatelessWidget {
const NavigationRouterExample({super.key});
@override
Widget build(BuildContext context) {
String appRoot = splash;
return MaterialApp(
title: 'Navigation Router Example',
theme: theme_data.ManageTheme().getTheme(context),
darkTheme: theme_data.ManageTheme().getDarkTheme(context),
themeMode: ThemeMode.light,
initialRoute: appRoot,
onGenerateRoute: (settings) =>
generateRoute(settings),
debugShowCheckedModeBanner: false,
);
}
}
DartThis was easy. We are following a default approach for navigation in Flutter for that we used the onGenerateRoute property where we will decide all our navigation.
initialRoute: appRoot,
This will set the initial root for the app. We set the Splash screen for app’s initial route. The appRoot is content that we defined in a separate file.
Create a new file <project_dir>/lib/utilities/constants/app_route_constant.dart
const String splash = "splashScreen";
const String login = "loginScreen";
const String register = "registerScreen";
const String dashboard ="dashboardScreen";
DartWe used the theme configuration as well. If you want to know more about theme configuration you can check the theme setup guide.
In our navigation_router_example.dart file we have a function generateRoute. We need to add our logic for navigation in this. For that create a new file <product_dir>/lib/utilities/app_navigation.dart
import 'package:navigationrouterexample/view/screens/splash_screen.dart';
import 'package:navigationrouterexample/view/screens/auth/login_screen.dart';
import 'package:navigationrouterexample/view/screens/auth/register_screen.dart';
import 'package:navigationrouterexample/view/screens/auth/dashboard_screen.dart';
import 'package:navigationrouterexample/utilities/constants/app_route_constants.dart';
Route<dynamic> generateRoute(RouteSettings routeSettings) {
switch (routeSettings.name) {
case splash:
return MaterialPageRoute(builder: (_) => const SplashScreen());
case login:
return MaterialPageRoute(builder: (_) => const LoginScreen());
case register:
return MaterialPageRoute(builder: (_) => const RegisterScreen());
case dashboard:
return MaterialPageRoute(builder: (_) => const DashboardScreen());
}
}
DartWe have set up all the navigation. Now the last step is how to navigate on these routers. We will handle the initial navigation in the splash screen. While loading an app we will check if the user is logged in or not. Based on the login state we will redirect the user to either the dashboard or login screen.
Edit the <project_dir>/view/screens/splash_screen.dart
import 'dart:async';
import 'package:navigationrouterexample/provider/user_provider.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:lottie/lottie.dart';
import 'package:brahmkshatirya/utilities/constants/app_route_constants.dart';
class SplashScreen extends ConsumerStatefulWidget {
const SplashScreen({super.key});
@override
ConsumerState<SplashScreen> createState() {
return _SplashScreenState();
}
}
class _SplashScreenState extends ConsumerState<SplashScreen> {
@override
void initState() {
_navigateHomepage(context);
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primary),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
SizedBox(
width: MediaQuery.of(context).size.width / 1.5,
child: Image.asset('assets/images/logoCenter.png')), // You can show the app logo
Lottie.asset('assets/images/lottie/loading_animation.json') // A login animation using lottie files.
],
),
),
),
);
}
// Handle the navigation logic
_navigateHomepage(BuildContext context) async {
Timer(const Duration(seconds: 3), () async {
final userProvider =
await ref.read(userAuthProvider.notifier).loadAuthData(); // We checked the authientication using riverpod.
if (userProvider != null &&
userProvider.isLogedIn &&
userProvider.token != "") {
if (!context.mounted) return;
await Navigator.pushReplacementNamed(context, dashboard);
}
if (!context.mounted) return;
await Navigator.pushReplacementNamed(context, login);
});
}
}
navigationrouterexample/view/screens/splash_screen.dartThat’s all. In the _navigateHomepage method, we checked if a user is logged in or not using Riverpod state management. How to manage auth using Riverpod is out of context from this article. If the user is logged in we use the Navigator.pushReplacementNamed to navigate to named routers. This is how we can use Flutter Navigation using routers.