Flutter Navigator 2.0 with Router
In this article, We are going to understand how to implement flutter navigator 2.0 with router in flutter applications. You can also check out flutter navigator 2.0 without router at HERE.
The Router API is used to provide underlying platform to handle routes in flutter apps. We can parse browser URL to display page using Router. In this flutter example, we are displaying football clubs names in the list UI. On click of list item, we will display details screen.
Page is used to set navigator’s history stack. RouteInformtionParser is used to take RouteInformation from RouteInformationProvider and parse into user defined datatype.
RouterDelegate is used to detect changes in app state and responds them. It builds navigator with current list of pages. BackButtonDispatcher is used to report back button press to router.
Create Model Class
final String clubName;
final String countryName;
SoccerClub(this.clubName, this.countryName);
}
Create App Class for Flutter Navigator
import ‘soccer_club_route_information_parser.dart’;
import ‘soccer_club_router_delegate.dart’;
class SoccerClubsApp extends StatefulWidget {
@override
State<StatefulWidget> createState() => _SoccerClubsAppState();
}
class _SoccerClubsAppState extends State<SoccerClubsApp> {
SoccerClubRouterDelegate soccerClubRouterDelegate = SoccerClubRouterDelegate();
SoccerClubRouteInformationParser soccerClubRouteInformationParser =
SoccerClubRouteInformationParser();
@override
Widget build(BuildContext context) {
return MaterialApp.router(
debugShowCheckedModeBanner: false,
routerDelegate: soccerClubRouterDelegate,
routeInformationParser: soccerClubRouteInformationParser,
);
}
}
Create Pages for Flutter Navigator
import ‘soccer_club.dart’;
import ‘soccer_club_details_page.dart’;
import ‘soccer_club_route_path.dart’;
import ‘soccer_clubs_list_screen.dart’;
import ‘unknown_screen.dart’;
class SoccerClubRouterDelegate extends RouterDelegate<SoccerClubRoutePath>
with ChangeNotifier, PopNavigatorRouterDelegateMixin<SoccerClubRoutePath> {
final GlobalKey<NavigatorState> navigatorKey;
SoccerClub selectedSoccerClub;
bool show404 = false;
List<SoccerClub> listSoccerClubs = [
SoccerClub(‘Real Madrid’, ‘Spain’),
SoccerClub(‘Paris Saint-Germain’, ‘France’),
SoccerClub(‘Manchester City’, ‘England’),
SoccerClub(‘Bayern Munich’, ‘Germany’),
];
SoccerClubRouterDelegate() : navigatorKey = GlobalKey<NavigatorState>();
SoccerClubRoutePath get currentConfiguration {
if (show404) {
return SoccerClubRoutePath.unknown();
}
return selectedSoccerClub == null
? SoccerClubRoutePath.home()
: SoccerClubRoutePath.details(listSoccerClubs.indexOf(selectedSoccerClub));
}
@override
Widget build(BuildContext context) {
return Navigator(
key: navigatorKey,
pages: [
MaterialPage(
key: ValueKey(‘SoccerClubsListPage’),
child: SoccerClubsListScreen(
listSoccerClubs: listSoccerClubs,
onTapped: handleSoccerClubTapped,
),
),
if (show404)
MaterialPage(key: ValueKey(‘UnknownPage’), child: UnknownScreen())
else if (selectedSoccerClub != null)
SoccerClubDetailsPage(soccerClub: selectedSoccerClub)
],
onPopPage: (route, result) {
if (!route.didPop(result)) {
return false;
}
selectedSoccerClub = null;
show404 = false;
notifyListeners();
return true;
},
);
}
@override
Future<void> setNewRoutePath(SoccerClubRoutePath path) async {
if (path.isUnknown) {
selectedSoccerClub = null;
show404 = true;
return;
}
if (path.isDetailsPage) {
if (path.id < 0 || path.id > listSoccerClubs.length – 1) {
show404 = true;
return;
}
selectedSoccerClub = listSoccerClubs[path.id];
} else {
selectedSoccerClub = null;
}
show404 = false;
}
void handleSoccerClubTapped(SoccerClub soccerClub) {
selectedSoccerClub = soccerClub;
notifyListeners();
}
}
Create List Screen
import ‘soccer_club.dart’;
class SoccerClubsListScreen extends StatelessWidget {
final List<SoccerClub> listSoccerClubs;
final ValueChanged<SoccerClub> onTapped;
SoccerClubsListScreen({
@required this.listSoccerClubs,
@required this.onTapped,
});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(‘Flutter Navigator 2.0 Sample’),
),
body: ListView.separated(
separatorBuilder: (context, index) => Divider(
color: Colors.black,
),
itemCount: listSoccerClubs.length,
itemBuilder: (context, index) => GestureDetector(
child: Container(
padding: EdgeInsets.all(15),
child: Column(
children: [
Text(listSoccerClubs[index].clubName, style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold,),),
SizedBox(height: 15,),
Text(listSoccerClubs[index].countryName, style: TextStyle(fontSize: 20),),
],
),
),
onTap: () => onTapped(listSoccerClubs[index]),
)),
);
}
}
Create Details Screen
import ‘soccer_club.dart’;
import ‘soccer_club_details_screen.dart’;
class SoccerClubDetailsPage extends Page {
final SoccerClub soccerClub;
SoccerClubDetailsPage({
this.soccerClub,
}) : super(key: ValueKey(soccerClub));
Route createRoute(BuildContext context) {
return MaterialPageRoute(
settings: this,
builder: (BuildContext context) {
return SoccerClubDetailsScreen(soccerClub: soccerClub);
},
);
}
}
import ‘soccer_club.dart’;
class SoccerClubDetailsScreen extends StatelessWidget {
final SoccerClub soccerClub;
SoccerClubDetailsScreen({
@required this.soccerClub,
});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(child: Text(soccerClub.clubName, style: TextStyle(fontSize: 50, fontWeight: FontWeight.bold))),
);
}
}
Create Route Path Class for Flutter Navigator
final int id;
final bool isUnknown;
SoccerClubRoutePath.home()
: id = null,
isUnknown = false;
SoccerClubRoutePath.details(this.id) : isUnknown = false;
SoccerClubRoutePath.unknown()
: id = null,
isUnknown = true;
bool get isHomePage => id == null;
bool get isDetailsPage => id != null;
}
Create Route Information Parser Class
import ‘soccer_club_route_path.dart’;
class SoccerClubRouteInformationParser extends RouteInformationParser<SoccerClubRoutePath> {
@override
Future<SoccerClubRoutePath> parseRouteInformation(
RouteInformation routeInformation) async {
final uri = Uri.parse(routeInformation.location);
if (uri.pathSegments.length == 0) {
return SoccerClubRoutePath.home();
}
if (uri.pathSegments.length == 2) {
if (uri.pathSegments[0] != ‘soccer_club’) return SoccerClubRoutePath.unknown();
var remaining = uri.pathSegments[1];
var id = int.tryParse(remaining);
if (id == null) return SoccerClubRoutePath.unknown();
return SoccerClubRoutePath.details(id);
}
return SoccerClubRoutePath.unknown();
}
@override
RouteInformation restoreRouteInformation(SoccerClubRoutePath path) {
if (path.isUnknown) {
return RouteInformation(location: ‘/404’);
}
if (path.isHomePage) {
return RouteInformation(location: ‘/’);
}
if (path.isDetailsPage) {
return RouteInformation(location: ‘/soccer_club/${path.id}’);
}
return null;
}
}


Pingback: Navigation in Flutter with Example - CodingWithDhrumil
Pingback: Implementing Flutter Navigation & Routing - CodingWithDhrumil
Pingback: How to Create PDF Files in Flutter - CodingWithDhrumil