-
Couldn't load subscription status.
- Fork 3.5k
[go_router] Add ShellRoute #2453
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
977f6bc
2db67e6
9ffd006
4da1fa0
100b33e
2387883
0f75672
4cdb183
a15b50b
93ca770
3ca5bf4
608f83b
dcab29d
469745a
f9f8c30
0436f1a
4bc4330
8eaf4e2
d92ce85
c794b87
cc27334
0028006
3a70fa5
183eb6a
3c9d725
340a6ca
d2fdeb9
c8deee5
c3c8f66
2c4585b
92ed4ae
41f5b06
780483a
f064d72
0819d4d
25e3236
de67875
bf1bad0
f82248f
44b8afd
02fe72e
631fd10
b4b4ac8
2d067d7
029ad91
d4bb46a
fb89778
61ebdb0
46609b0
2712c11
f38fa49
692bc46
c70f33c
e304529
55677e9
6248077
9378fd5
de8f97c
429d08b
a86b8fe
9be299a
813695b
8749762
85a1a6d
424afa4
cc28a23
f564e61
e7e795a
6c7867a
73f4747
d35a25b
0cf265a
1288344
50a31f0
3a9f206
bf54d73
e9ff347
c0794a4
c6bbccd
9d109db
886bee7
26e0515
27fb0f5
e3d31f8
146ede5
73899f2
97584c3
adc610d
c9f670b
9d92bbe
fb36859
70048b8
1e37f8f
a7426b8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,236 @@ | ||
| // Copyright 2013 The Flutter Authors. All rights reserved. | ||
| // Use of this source code is governed by a BSD-style license that can be | ||
| // found in the LICENSE file. | ||
|
|
||
johnpryan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| import 'package:flutter/material.dart'; | ||
| import 'package:go_router/go_router.dart'; | ||
|
|
||
| final GlobalKey<NavigatorState> _rootNavigatorKey = | ||
| GlobalKey<NavigatorState>(debugLabel: 'root'); | ||
| final GlobalKey<NavigatorState> _shellNavigatorKey = | ||
| GlobalKey<NavigatorState>(debugLabel: 'shell'); | ||
|
|
||
| // This scenario demonstrates how to set up nested navigation using ShellRoute, | ||
| // which is a pattern where an additional Navigator is placed in the widget tree | ||
| // to be used instead of the root navigator. This allows deep-links to display | ||
| // pages along with other UI components such as a BottomNavigationBar. | ||
| // | ||
| // This example demonstrates how to display a route within a ShellRoute and also | ||
| // push a screen using a different navigator (such as the root Navigator) by | ||
| // providing a `parentNavigatorKey`. | ||
|
|
||
| void main() { | ||
| runApp(ShellRouteExampleApp()); | ||
| } | ||
|
|
||
| /// An example demonstrating how to use [ShellRoute] | ||
|
||
| class ShellRouteExampleApp extends StatelessWidget { | ||
| /// Creates a [ShellRouteExampleApp] | ||
| ShellRouteExampleApp({Key? key}) : super(key: key); | ||
|
|
||
| final GoRouter _router = GoRouter( | ||
| navigatorKey: _rootNavigatorKey, | ||
| initialLocation: '/a', | ||
| routes: <RouteBase>[ | ||
| /// Application shell | ||
| ShellRoute( | ||
| navigatorKey: _shellNavigatorKey, | ||
| builder: (BuildContext context, GoRouterState state, Widget child) { | ||
| return ScaffoldWithNavBar(child: child); | ||
| }, | ||
| routes: <RouteBase>[ | ||
| /// The first screen to display in the bottom navigation bar. | ||
| GoRoute( | ||
| path: '/a', | ||
| builder: (BuildContext context, GoRouterState state) { | ||
| return const ScreenA(); | ||
| }, | ||
| routes: <RouteBase>[ | ||
| // The details screen to display stacked on the inner Navigator. | ||
| // This will cover screen A but not the application shell. | ||
| GoRoute( | ||
| path: 'details', | ||
| builder: (BuildContext context, GoRouterState state) { | ||
| return const DetailsScreen(label: 'A'); | ||
| }, | ||
| ), | ||
| ], | ||
| ), | ||
|
|
||
| /// Displayed when the second item in the the bottom navigation bar is | ||
| /// selected. | ||
| GoRoute( | ||
| path: '/b', | ||
| builder: (BuildContext context, GoRouterState state) { | ||
| return const ScreenB(); | ||
| }, | ||
| routes: <RouteBase>[ | ||
| /// Same as "/a/details", but displayed on the root Navigator by | ||
| /// specifying [parentNavigatorKey]. This will cover both screen B | ||
| /// and the application shell. | ||
| GoRoute( | ||
| path: 'details', | ||
| parentNavigatorKey: _rootNavigatorKey, | ||
| builder: (BuildContext context, GoRouterState state) { | ||
| return const DetailsScreen(label: 'B'); | ||
| }, | ||
| ), | ||
| ], | ||
| ), | ||
| ], | ||
| ), | ||
| ], | ||
| ); | ||
|
|
||
| @override | ||
| Widget build(BuildContext context) { | ||
| return MaterialApp.router( | ||
| title: 'Flutter Demo', | ||
| theme: ThemeData( | ||
| primarySwatch: Colors.blue, | ||
| ), | ||
| routeInformationParser: _router.routeInformationParser, | ||
| routerDelegate: _router.routerDelegate, | ||
| routeInformationProvider: _router.routeInformationProvider, | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| /// Builds the "shell" for the app by building a Scaffold with a | ||
| /// BottomNavigationBar, where [child] is placed in the body of the Scaffold. | ||
| class ScaffoldWithNavBar extends StatelessWidget { | ||
| /// Constructs an [ScaffoldWithNavBar]. | ||
| const ScaffoldWithNavBar({ | ||
| required this.child, | ||
| Key? key, | ||
| }) : super(key: key); | ||
|
|
||
| /// The widget to display in the body of the Scaffold. | ||
| /// In this sample, it is a Navigator. | ||
| final Widget child; | ||
|
|
||
| @override | ||
| Widget build(BuildContext context) { | ||
| return Scaffold( | ||
| body: child, | ||
| bottomNavigationBar: BottomNavigationBar( | ||
| items: const <BottomNavigationBarItem>[ | ||
| BottomNavigationBarItem( | ||
| icon: Icon(Icons.home), | ||
| label: 'A Screen', | ||
| ), | ||
| BottomNavigationBarItem( | ||
| icon: Icon(Icons.business), | ||
| label: 'B Screen', | ||
| ), | ||
| ], | ||
| currentIndex: _calculateSelectedIndex(context), | ||
| onTap: (int idx) => _onItemTapped(idx, context), | ||
| ), | ||
| ); | ||
| } | ||
|
|
||
| static int _calculateSelectedIndex(BuildContext context) { | ||
| final GoRouter route = GoRouter.of(context); | ||
| final String location = route.location; | ||
| if (location == '/a') { | ||
| return 0; | ||
| } | ||
| if (location == '/b') { | ||
| return 1; | ||
| } | ||
| return 0; | ||
| } | ||
|
|
||
| void _onItemTapped(int index, BuildContext context) { | ||
| switch (index) { | ||
| case 0: | ||
| GoRouter.of(context).go('/a'); | ||
| break; | ||
| case 1: | ||
| GoRouter.of(context).go('/b'); | ||
| break; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// The first screen in the bottom navigation bar. | ||
| class ScreenA extends StatelessWidget { | ||
| /// Constructs a [ScreenA] widget. | ||
| const ScreenA({Key? key}) : super(key: key); | ||
|
|
||
| @override | ||
| Widget build(BuildContext context) { | ||
| return Scaffold( | ||
| appBar: AppBar(), | ||
| body: Center( | ||
| child: Column( | ||
| mainAxisSize: MainAxisSize.min, | ||
| children: <Widget>[ | ||
| const Text('Screen A'), | ||
| TextButton( | ||
| onPressed: () { | ||
| GoRouter.of(context).go('/a/details'); | ||
| }, | ||
| child: const Text('View A details'), | ||
| ), | ||
| ], | ||
| ), | ||
| ), | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| /// The second screen in the bottom navigation bar. | ||
| class ScreenB extends StatelessWidget { | ||
| /// Constructs a [ScreenB] widget. | ||
| const ScreenB({Key? key}) : super(key: key); | ||
|
|
||
| @override | ||
| Widget build(BuildContext context) { | ||
| return Scaffold( | ||
| appBar: AppBar(), | ||
| body: Center( | ||
| child: Column( | ||
| mainAxisSize: MainAxisSize.min, | ||
| children: <Widget>[ | ||
| const Text('Screen B'), | ||
| TextButton( | ||
| onPressed: () { | ||
| GoRouter.of(context).go('/b/details'); | ||
| }, | ||
| child: const Text('View B details'), | ||
| ), | ||
| ], | ||
| ), | ||
| ), | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| /// The details screen for either the A or B screen. | ||
| class DetailsScreen extends StatelessWidget { | ||
| /// Constructs a [DetailsScreen]. | ||
| const DetailsScreen({ | ||
| required this.label, | ||
| Key? key, | ||
| }) : super(key: key); | ||
|
|
||
| /// The label to display in the center of the screen. | ||
| final String label; | ||
|
|
||
| @override | ||
| Widget build(BuildContext context) { | ||
| return Scaffold( | ||
| appBar: AppBar( | ||
| title: const Text('Details Screen'), | ||
| ), | ||
| body: Center( | ||
| child: Text( | ||
| 'Details for $label', | ||
| style: Theme.of(context).textTheme.headlineMedium, | ||
| ), | ||
| ), | ||
| ); | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.