Created
June 21, 2022 15:29
-
-
Save daanporon/c57044894b71bbf6e7c121387d3a0b31 to your computer and use it in GitHub Desktop.
Routemaster example with subnavigation and tabbed navigation
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/cupertino.dart'; | |
import 'package:flutter/material.dart'; | |
import 'package:routemaster/routemaster.dart'; | |
buildProductRoutes(String product) { | |
final routes = <String, PageBuilder>{}; | |
routes['/home/$product'] = (_) => const Redirect('/home'); | |
routes['/home/$product/:pid'] = (_) => CupertinoTabPage( | |
child: ScreenWithBottomNav(product: product), | |
paths: [ | |
'/home/$product/:pid/tab-a', | |
'/home/$product/:pid/tab-b', | |
'/home/$product/:pid/tab-c' | |
], | |
); | |
routes['/home/$product/:pid/tab-a'] = (_) => const MaterialPage( | |
child: Screen( | |
name: 'Tab A', | |
key: ValueKey( | |
'A', | |
), | |
appBarEnabled: true, | |
appBarHome: true, | |
), | |
); | |
routes['/home/$product/:pid/tab-b'] = (_) => TabPage( | |
child: const ScreenWithTabs(), | |
paths: ['/home/$product/:pid/tab-b/1', '/home/$product/:pid/tab-b/2'], | |
); | |
routes['/home/$product/:pid/tab-b/1'] = (_) => const MaterialPage( | |
child: Screen( | |
name: 'B.1', | |
key: ValueKey( | |
'B.1', | |
), | |
), | |
); | |
routes['/home/$product/:pid/tab-b/2'] = (_) => const MaterialPage( | |
child: Screen( | |
name: 'B.2', | |
key: ValueKey( | |
'B.2', | |
), | |
), | |
); | |
routes['/home/$product/:pid/tab-c'] = | |
(_) => Redirect('/home/$product/:pid/tab-c/1'); | |
routes['/home/$product/:pid/tab-c/1'] = (_) => MaterialPage( | |
child: Screen( | |
name: 'C.1', | |
appBarEnabled: true, | |
appBarHome: true, | |
key: const ValueKey( | |
'C.1', | |
), | |
onPressed: (context) => Routemaster.of(context).push('2'), | |
), | |
); | |
routes['/home/$product/:pid/tab-c/1/2'] = (_) => const MaterialPage( | |
child: Screen( | |
name: 'C.2', | |
appBarEnabled: true, | |
key: ValueKey( | |
'C.2', | |
), | |
), | |
); | |
return routes; | |
} | |
final RouteMap _routeMap = RouteMap( | |
routes: { | |
'/': (_) => const MaterialPage(child: StartScreen()), | |
'/home': (_) => const MaterialPage(child: HomeScreen()), | |
...buildProductRoutes('product-a'), | |
...buildProductRoutes('product-b'), | |
}, | |
); | |
void main() { | |
runApp(const App()); | |
} | |
class App extends StatelessWidget { | |
const App({ | |
Key? key, | |
}) : super(key: key); | |
// This widget is the root of your application. | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp.router( | |
title: 'Flutter Demo', | |
theme: ThemeData( | |
primarySwatch: Colors.blue, | |
), | |
routerDelegate: | |
RoutemasterDelegate(routesBuilder: (context) => _routeMap), | |
routeInformationParser: const RoutemasterParser(), | |
); | |
} | |
} | |
class StartScreen extends StatelessWidget { | |
const StartScreen({Key? key}) : super(key: key); | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar( | |
title: const Text('Start page'), | |
), | |
body: Center( | |
child: Column( | |
mainAxisAlignment: MainAxisAlignment.center, | |
children: [ | |
'/home', | |
'/home/product-a/1234/tab-b', | |
'/home/product-a/1234/tab-b/1', | |
'/home/product-a/1234/tab-b/2', | |
'/home/product-b/456/tab-c/1/2', | |
] | |
.map( | |
(route) => ElevatedButton( | |
onPressed: () => Routemaster.of(context).push(route), | |
child: Text(route), | |
), | |
) | |
.toList(), | |
), | |
), | |
); | |
} | |
} | |
class HomeScreen extends StatelessWidget { | |
const HomeScreen({Key? key}) : super(key: key); | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar( | |
title: const Text('Home page'), | |
), | |
body: Center( | |
child: Column( | |
mainAxisAlignment: MainAxisAlignment.center, | |
children: <Widget>[ | |
ElevatedButton( | |
onPressed: () => Routemaster.of(context).push('product-a/1234'), | |
child: const Text('Product A'), | |
), | |
ElevatedButton( | |
onPressed: () => Routemaster.of(context).push('product-b/456'), | |
child: const Text('Product B'), | |
), | |
], | |
), | |
), | |
); | |
} | |
} | |
class ScreenWithBottomNav extends StatelessWidget { | |
final String product; | |
const ScreenWithBottomNav({ | |
Key? key, | |
required this.product, | |
}) : super(key: key); | |
@override | |
Widget build(BuildContext context) { | |
final tabState = CupertinoTabPage.of(context); | |
return CupertinoTabScaffold( | |
controller: tabState.controller, | |
tabBuilder: tabState.tabBuilder, | |
tabBar: CupertinoTabBar( | |
items: const [ | |
BottomNavigationBarItem( | |
icon: Icon(Icons.tab), | |
label: 'Tab A', | |
), | |
BottomNavigationBarItem( | |
icon: Icon(Icons.tab), | |
label: 'Tab B', | |
), | |
BottomNavigationBarItem( | |
icon: Icon(Icons.tab), | |
label: 'Tab C', | |
), | |
], | |
), | |
); | |
} | |
} | |
class Screen extends StatelessWidget { | |
final String name; | |
final bool appBarEnabled; | |
final bool appBarHome; | |
final void Function(BuildContext)? onPressed; | |
const Screen({ | |
Key? key, | |
required this.name, | |
this.appBarEnabled = false, | |
this.appBarHome = false, | |
this.onPressed, | |
}) : super(key: key); | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: appBarEnabled | |
? AppBar( | |
leading: appBarHome | |
? BackButton( | |
onPressed: () => Routemaster.of(context) | |
.popUntil((routeData) => routeData.path == '/home'), | |
) | |
: null, | |
) | |
: null, | |
body: Center( | |
child: Column( | |
mainAxisAlignment: MainAxisAlignment.center, | |
children: [ | |
Text(RouteData.of(context).path), | |
Text(RouteData.of(context).pathParameters.toString()), | |
Text(RouteData.of(context).queryParameters.toString()), | |
Text(appBarHome.toString()), | |
Text('Screen $name'), | |
if (onPressed != null) | |
ElevatedButton( | |
onPressed: () => onPressed?.call(context), | |
child: const Text('Press me'), | |
) | |
], | |
), | |
), | |
); | |
} | |
} | |
class ScreenWithTabs extends StatelessWidget { | |
const ScreenWithTabs({ | |
Key? key, | |
}) : super(key: key); | |
@override | |
Widget build(BuildContext context) { | |
final tabState = TabPage.of(context); | |
return Scaffold( | |
appBar: AppBar( | |
leading: BackButton( | |
onPressed: () => Routemaster.of(context) | |
.popUntil((routeData) => routeData.path == '/home'), | |
), | |
bottom: TabBar( | |
controller: tabState.controller, | |
tabs: const [ | |
Tab(icon: Icon(Icons.tab), text: 'B1'), | |
Tab(icon: Icon(Icons.tab), text: 'B2'), | |
], | |
), | |
), | |
body: TabBarView( | |
controller: tabState.controller, | |
children: [ | |
for (final stack in tabState.stacks) PageStackNavigator(stack: stack), | |
], | |
), | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment