An open-source framework called Flutter is used to create powerful, cross-platform mobile apps. The navigation system is one of the most crucial components of any mobile application. Routes a user-friendly and highly customizable navigation system is offered by Flutter. We’ll go into great detail about creating routes in Flutter in this blog .
An application with multiple pages is one in which we design screens with their own widgets one of which is always visible.
The screens are typically displayed in response to user interactions which is accomplished by using navigational functionalities.
What is Navigation?
In a Flutter application switching between screens or views is referred to as “navigation”. Any mobile application must have navigation because it allows users to move between the app’s various screens and interact with its features.
Each screen or view in Flutter is represented by a widget and navigation is accomplished by stacking routes. The previous screen is pushed onto the stack and the new screen is displayed when a user navigates to a new screen.
To implement navigation in an application Flutter offers various patterns and methods including:
Navigator widgets : The Navigator widget in Flutter controls a stack of Route objects that stand in for the app’s screens. It offers ways for developers to push and pop routes from the stack, allowing them to manage the application’s flow.
Named routes: Named routes let app developers give each screen in their application a special name so that users can find it using the Navigator.pushNamed() method.
Bottom navigation bar: A bottom navigation bar is a widget that enables users to quickly switch between the app’s various screens by displaying a list of icons or labels at the bottom of the screen.
Tabs: Users can switch between various categories or views on screen by using tabs which offer a horizontal list of tab labels.
Drawer: A drawer is a panel that slides out from the side of the screen and gives the user access to a list of navigation options.
These methods enable programmers to integrate flexible and user-friendly navigation system into their Flutter applications resulting in a seamless user experience.
What are Routes?
Routes in Flutter are a way for users to move between different screens or pages of your application. A widget and distinct route are used to represent each screen in your application. Push and pop operations, which are used to move around a stack, can be used to navigate routes.
The current screen is pushed onto a stack of screens when a user switches between them. The current screen is removed from the stack and the previous screen is shown when the user requests to return to the previous screen.
Making a Simple Route
In Flutter, building a simple route is very easy. Simply defining a widget to represent your screen and link it to a route name is all that is required.
Say we want to move from the home screen to the settings screen. We must create a new widget that represents the settings screen in order to create a route for the settings screen.
Here’s an illustration:
import 'package:flutter/material.dart';
class SettingsScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Settings'),
),
body: Center(
child: Text('Settings Screen'),
),
);
}
}
Here… for an example is :In the previous illustration, we create a new widget called SettingsScreen that shows a straightforward screen with appBar and text widget in the center.
We must give our widget a route name now that we have it. The MaterialPageRoute class which generates a route that shows a full-screen modal dialog, can be used to achieve this. To create a route for our SettingsScreen, follow these steps:
MaterialPageRoute(
builder: (context) => SettingsScreen(),
);
In the previous example a fresh MaterialPageRoute is made and connected to our SettingsScreen widget. callback function returns our widget builder parameter.
Choosing a Route to Follow
We can navigate to our route from our home screen now that we have defined it. The Navigator widget, which controls the navigation stack must be used in order to accomplish this.
Using the Navigator.push() method we can add a fresh route to the stack. Here an illustration:
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SettingsScreen()),
);
In the aforementioned example we call the Navigator.push() method passing the current BuildContext and our MaterialPageRoute object.
Pop the Route
To go back to the previous screen we can use the Navigator.pop() method. This method returns any data passed to the route along with the top route that was pulled from the navigation stack. Here’s an illustration:
Navigator.pop(context);
In the previous illustration, we used the Navigator.Using the pop() method, send the current BuildContext. This will take you back to the previous screen and pop the top route from the navigation stack
By assigning each route a distinct name, named routing organizes your app’s navigation and makes it simpler to move between screens. Named routing offers a way to navigate to a specific screen by using a named route as opposed to using the widget hierarchy.
The use of named routing in Flutter including how to define named routes pass data between screens, and handle route transitions will be covered in this blog.
Defining Named Routes
To use named routing in Flutter, you first need to define your routes. This is done in the main.dart file of your app, in the MaterialApp widget. The routes parameter, which is a map of String keys and WidgetBuilder values, is where you define your routes.
Let’s say, for illustration purposes, that our app has two screens: a home screen and a details screen. Our named routes can be described as follows:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My App',
initialRoute: '/',
routes: {
'/': (context) => FirstScreen(),
'/second': (context) => SecondScreen(),
},
);
}
}
here defined two routes in the example: “/” for the first screen and “/secondScreen” for the second screen. here, we set the initialRoute to “/,” which is the when app launch on the first screen.
Named routes
We defined here two routes in this example : “/” for the home screen and
“/details” for the details screen define . Additionally we set the initial Route to “/” which causes the app launch on the homeScreen.
Making your way to named routes
The Navigator.pushNamed() method which accepts the route name as a parameter can be used to navigate to a named route.
For instance we could follow these steps to move from the home screen to the details screen:
Navigator.pushNamed(context, '/details'');
By doing this the user would see the details screen . it would be pushed onto the navigation stack.
Data Transfer between Screens in named routes
You’ll frequently need to pass data between your applocations screens. By passing arguments to the Navigator.pushNamed() method .Let’s say, for illustration that we want to pass the selected item to the details screen from a list of items on the home screen. By giving the item to the Navigator as an argument. we can accomplish this. the pushNamed() function.
Navigator.pushNamed(context, '/details', arguments: item);
class FirstScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
final item = ModalRoute.of(context)!.settings.arguments as Item;
return Scaffold(
appBar: AppBar(
title: Text(data.title),
),
body: Center(
child: Text(data.description),
),
);
}
Managing Route Changes
You can design the way that screens transition within your app in addition to naming routes and getting there. This can be accomplished by specifying a unique transition animation for each route using the MaterialPageRoute function Object() { [native code] }.
Take a fade-in transition, for instance, which we might want to use for the details screen. Making a new MaterialPageRoute and setting its transitionDuration and pageBuilder properties would allow us to accomplish this:
When switching between screens, Flutter offers a variety of built-in transition animations that can be used. There are many of these, such as FadeTransition, SlideTransition, and ScaleTransition. By extending the MaterialPageRoute class and overriding the buildTransitions method, you can also produce your own original transition animation.
class SlideRightRoute extends PageRouteBuilder {
final Widget page;
SlideRightRoute({required this.page})
: super(
transitionDuration: Duration(milliseconds: 500),
transitionsBuilder: (context, animation, secondaryAnimation, child) {
var begin = Offset(1.0, 0.0);
var end = Offset.zero;
var tween = Tween(begin: begin, end: end);
var offsetAnimation = animation.drive(tween);
return SlideTransition(
position: offsetAnimation,
child: child,
);
},
pageBuilder: (context, animation, secondaryAnimation) => page,
);
}
Navigator.push(
context,
SlideRightRoute(page: DetailsScreen()),
);
We create a new SlideRightRoute class that extends PageRouteBuilder in the aforementioned example. In order to create a SlideTransition that slides the screen in from the right, we define the transitionsBuilder method and set the transitionDuration property to 500 milliseconds. The Navigator.push method then receives our custom route as a parameter.
Choosing a Different Transition Duration
The duration of the route transition animation can be set using the transitionDuration property. You can change the value from the default of 300 milliseconds to one of your choosing.
For instance, we could modify the transitionDuration property as follows to make our custom slide-in-right transition last for 750 milliseconds:
class SlideRightRoute extends PageRouteBuilder {
SlideRightRoute({required Widget page})
: super(
transitionDuration: Duration(milliseconds: 750),
transitionsBuilder: (context, animation, secondaryAnimation, child) {
//...
},
pageBuilder: (context, animation, secondaryAnimation) => page,
);
}
defaultRouteName
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My App',
initialRoute: '/',
routes: {
'/': (context) => HomeScreen(),
'/second': (context) => SecondScreen(),
},
);
}
}
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Home')),
body: Center(
child: RaisedButton(
child: Text('Go to Second Screen'),
onPressed: () {
Navigator.pushNamed(context, '/second');
},
),
),
);
}
}
class SecondScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Second Screen')),
body: Center(
child: RaisedButton(
child: Text('Go back to Home Screen'),
onPressed: () {
Navigator.pop(context);
},
),
),
);
}
}
The HomeScreen widget will be the first screen to be displayed when the programme is opened because the defaultRouteName attribute in this example is set to ‘/’. Each route in the app has a widget attached to it that should appear when the route is browsed to. These routes are defined by the routes parameter.
The Second’ route, which is represented by the SecondScreen widget is reached via the Navigator.pushNamed function. To return to the previous screen which in this instance is the HomeScreen widget use the Navigator.pop function.
PushReplacementNamed
PushReplacementNamed is a method in Flutter , that lets you switch to a new screen while erasing the one that is currently on the navigation stack.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My App',
initialRoute: '/',
routes: {
'/': (context) => HomeScreen(),
'/second': (context) => SecondScreen(),
'/third': (context) => ThirdScreen(),
},
);
}
}
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Home')),
body: Center(
child: RaisedButton(
child: Text('Go to Second Screen'),
onPressed: () {
Navigator.pushReplacementNamed(context, '/second');
},
),
),
);
}
}
class SecondScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Second Screen')),
body: Center(
child: RaisedButton(
child: Text('Go to Third Screen'),
onPressed: () {
Navigator.pushReplacementNamed(context, '/third');
},
),
),
);
}
}
class ThirdScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Third Screen')),
body: Center(
child: RaisedButton(
child: Text('Go back to Home Screen'),
onPressed: () {
Navigator.popUntil(context, ModalRoute.withName('/'));
},
),
),
);
}
}
The HomeScreen and SecondScreen widgets in this example employ the pushReplacementNamed function to direct the user to the second and third routes, respectively. The current screen in the navigation stack gets replaced with the new screen when pushReplacementNamed is invoked.
The popUntil function is used by the ThirdScreen widget to return to the HomeScreen widget. The ModalRoute.withName(‘/’) predicate in this example matches the initial route, and the popUntil function continually pops the current route off the stack until the predicate supplied in its argument is true.
popAndPushNamed
Pop the current screen off the navigation stack and push a new screen onto the stack all at once with Flutter’s popAndPushNamed function.
Here’s an illustration:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My App',
initialRoute: '/',
routes: {
'/': (context) => HomeScreen(),
'/second': (context) => SecondScreen(),
'/third': (context) => ThirdScreen(),
},
);
}
}
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Home')),
body: Center(
child: RaisedButton(
child: Text('Go to Second Screen'),
onPressed: () {
Navigator.popAndPushNamed(context, '/second');
},
),
),
);
}
}
class SecondScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Second Screen')),
body: Center(
child: RaisedButton(
child: Text('Go to Third Screen'),
onPressed: () {
Navigator.pushNamed(context, '/third');
},
),
),
);
}
}
class ThirdScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Third Screen')),
body: Center(
child: RaisedButton(
child: Text('Go back to Home Screen'),
onPressed: () {
Navigator.popUntil(context, ModalRoute.withName('/'));
},
),
),
);
}
}
In this illustration the HomeScreen widget popAndPushNamed function is used to simultaneously pop the active screen off the stack and put the “second” route into the stack. When you wish to replace the current screen with new one while also removing the current screen from the navigation stack this is useful.
When you wish to mimic a “refresh” of the current screen by replacing it with a new instance of the same screen, the popAndPushNamed function might be helpful.
pushNamedAndRemoveUntil
PushNamedAndRemoveUntil is a method in Flutter that lets you advance to a new screen while erasing all previous screens from the stack of screens you’re currently on, up until a certain condition is satisfied.
Here’s an illustration:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My App',
initialRoute: '/',
routes: {
'/': (context) => HomeScreen(),
'/second': (context) => SecondScreen(),
'/third': (context) => ThirdScreen(),
},
);
}
}
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Home')),
body: Center(
child: RaisedButton(
child: Text('Go to Third Screen and remove previous screens'),
onPressed: () {
Navigator.pushNamedAndRemoveUntil(context, '/third', ModalRoute.withName('/'));
},
),
),
);
}
}
class SecondScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Second Screen')),
body: Center(
child: RaisedButton(
child: Text('Go to Third Screen'),
onPressed: () {
Navigator.pushNamed(context, '/third');
},
),
),
);
}
}
class ThirdScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Third Screen')),
body: Center(
child: RaisedButton(
child: Text('Go back to Home Screen'),
onPressed: () {
Navigator.popUntil(context, ModalRoute.withName('/'));
},
),
),
);
}
}
The HomeScreen widget in this example uses the pushNamedAndRemoveUntil function to browse to the “third” route and delete all previous screens from the navigation stack. A RoutePredicate is used as the second input to pushNamedAndRemoveUntil, and it defines the prerequisite for halting the removal of earlier routes. ModalRoute.withName(‘/’) in this situation is used to indicate that any routes that come before the ‘/’ route (the first route) should be dropped.
When you wish to start again with new screen after removing a number of screens from the navigation stack . the pushNamedAndRemoveUntil function might be helpful. When creating logout function for instance you could wish to utilize. it to delete all screens associated with the user’s session and start again with the login screen.
restorablePopAndPushNamed
With the help of the Flutter method restorablePopAndPushNamed you can move to a named route while simultaneously deleting the current route from the navigation stack and saving it for later restoration. Here is an illustration of how to use Flutter’s restorablePopAndPushNamed with named routes:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My App',
initialRoute: '/',
routes: {
'/': (context) => HomeScreen(),
'/settings': (context) => SettingsScreen(),
},
);
}
}
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home Screen'),
),
body: Center(
child: ElevatedButton(
child: Text('Go to Settings'),
onPressed: () {
Navigator.restorablePopAndPushNamed(context, '/settings');
},
),
),
);
}
}
class SettingsScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Settings Screen'),
),
body: Center(
child: ElevatedButton(
child: Text('Go back to Home'),
onPressed: () {
Navigator.restorablePop(context);
},
),
),
);
}
}
Two arguments are required by restorablePopAndPushNamed: a BuildContext and a String specifying the name of the route to be navigated to. It removes the current route from the navigation stack and replaces it with the named route.
RestorablePop pops the current route off the navigation stack and goes back to the previous screen with just a BuildContext argument.
Conclusion 👍
We thoroughly examined how to create routes in Flutter in this blog post. Routes are a way to move between screens or pages in your application, and we discovered that each screen is represented by a widget and connected to a particular route.
Additionally, we learned how to create a fundamental route, how to use the Navigator.push() method to travel to a route, and how to return.
Thanks for reading this article…..
Have a good day……