Last active
September 24, 2024 18:17
-
-
Save SEGVeenstra/0b1afa02bc35f4afe34b76951c10b94b to your computer and use it in GitHub Desktop.
GoRouter - reusable routes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/material.dart'; | |
import 'package:go_router/go_router.dart'; | |
void main() { | |
runApp(const MyApp()); | |
} | |
class MyApp extends StatelessWidget { | |
const MyApp({super.key}); | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp.router( | |
debugShowCheckedModeBanner: false, | |
routerConfig: myRouter, | |
); | |
} | |
} | |
class MyTabPage extends StatelessWidget { | |
const MyTabPage({ | |
required this.child, | |
super.key, | |
}); | |
final Widget child; | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar( | |
actions: [ | |
IconButton( | |
icon: Icon(Icons.person), | |
onPressed: () { | |
print(context.currentPath); | |
GoRouter.of(context).go( | |
context.currentPath == '/list' ? '/list/account' : '/account', | |
); | |
}, | |
), | |
], | |
), | |
body: child, | |
bottomNavigationBar: NavigationBar( | |
selectedIndex: context.currentPath.startsWith('/list') ? 1 : 0, | |
onDestinationSelected: (index) { | |
if (index == 0) GoRouter.of(context).go('/'); | |
if (index == 1) GoRouter.of(context).go('/list'); | |
}, | |
destinations: const [ | |
NavigationDestination( | |
icon: Icon(Icons.home), | |
label: 'Home', | |
), | |
NavigationDestination( | |
icon: Icon(Icons.list), | |
label: 'Items', | |
), | |
], | |
), | |
); | |
} | |
} | |
class MyTabContent extends StatelessWidget { | |
const MyTabContent({ | |
required this.name, | |
super.key, | |
}); | |
final String name; | |
@override | |
Widget build(BuildContext context) { | |
return Center( | |
child: Text(name), | |
); | |
} | |
} | |
class AccountPage extends StatelessWidget { | |
const AccountPage({ | |
required this.name, | |
super.key, | |
this.hasSubButton = false, | |
}); | |
final String name; | |
final bool hasSubButton; | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
backgroundColor: Colors.blueGrey, | |
appBar: AppBar(), | |
body: Center( | |
child: Column( | |
children: [ | |
Text(name), | |
if (hasSubButton) | |
ElevatedButton( | |
onPressed: () => | |
GoRouter.of(context).go(context.currentPath + '/sub'), | |
child: Text('Sub page'), | |
), | |
], | |
), | |
), | |
); | |
} | |
} | |
final rootKey = GlobalKey<NavigatorState>(); | |
final tabKey = GlobalKey<NavigatorState>(); | |
final myRouter = GoRouter( | |
routes: mainRoutes, | |
navigatorKey: rootKey, | |
); | |
final mainRoutes = [ | |
ShellRoute( | |
navigatorKey: tabKey, | |
builder: (context, state, child) => MyTabPage(child: child), | |
routes: [ | |
GoRoute( | |
path: '/', | |
builder: (context, state) => const MyTabContent(name: 'Home'), | |
routes: [ | |
accountsRoute, | |
], | |
), | |
GoRoute( | |
path: '/list', | |
builder: (context, state) => const MyTabContent(name: 'List'), | |
routes: [ | |
accountsRoute, | |
], | |
), | |
], | |
), | |
]; | |
// This is the trick. | |
// You can just create a full configured sub-tree. | |
final accountsRoute = GoRoute( | |
parentNavigatorKey: rootKey, | |
path: 'account', | |
builder: (context, state) => AccountPage( | |
name: 'Account', | |
hasSubButton: true, | |
), | |
routes: [ | |
GoRoute( | |
parentNavigatorKey: rootKey, | |
path: 'sub', | |
builder: (context, state) => AccountPage( | |
name: 'sub', | |
), | |
), | |
], | |
); | |
extension on BuildContext { | |
String get currentPath => | |
GoRouter.of(this).routeInformationProvider.value.uri.path; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment