Skip to content

Commit 9cc06ac

Browse files
authored
[go_router] Documentation for StatefulShellRoute (flutter#6308)
Adds documentation about StatefulShellRoute to the Configuration topic (configuration.md). Fixes flutter#127209.
1 parent 1b9195b commit 9cc06ac

File tree

5 files changed

+122
-4
lines changed

5 files changed

+122
-4
lines changed

packages/go_router/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 14.2.2
2+
3+
- Adds section for "Stateful nested navigation" to configuration.md.
4+
15
## 14.2.1
26

37
- Makes GoRouterState lookup more robust.

packages/go_router/doc/configuration.md

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,105 @@ For a complete example, see the [ShellRoute
152152
sample](https://github.com/flutter/packages/tree/main/packages/go_router/example/lib/shell_route.dart)
153153
in the example/ directory.
154154

155+
# Stateful nested navigation
156+
In addition to using nested navigation with for instance a BottomNavigationBar,
157+
many apps also require that state is maintained when navigating between
158+
destinations. To accomplish this, use [StatefulShellRoute][] instead of
159+
`ShellRoute`.
160+
161+
StatefulShellRoute creates separate `Navigator`s for each of its nested [branches](https://pub.dev/documentation/go_router/latest/go_router/StatefulShellBranch-class.html)
162+
(i.e. parallel navigation trees), making it possible to build an app with
163+
stateful nested navigation. The constructor [StatefulShellRoute.indexedStack](https://pub.dev/documentation/go_router/latest/go_router/StatefulShellRoute/StatefulShellRoute.indexedStack.html)
164+
provides a default implementation for managing the branch navigators, using an
165+
`IndexedStack`.
166+
167+
When using StatefulShellRoute, routes aren't configured on the shell route
168+
itself. Instead, they are configured for each of the branches. Example:
169+
170+
<?code-excerpt "../example/lib/stateful_shell_route.dart (configuration-branches)"?>
171+
```dart
172+
branches: <StatefulShellBranch>[
173+
// The route branch for the first tab of the bottom navigation bar.
174+
StatefulShellBranch(
175+
navigatorKey: _sectionANavigatorKey,
176+
routes: <RouteBase>[
177+
GoRoute(
178+
// The screen to display as the root in the first tab of the
179+
// bottom navigation bar.
180+
path: '/a',
181+
builder: (BuildContext context, GoRouterState state) =>
182+
const RootScreen(label: 'A', detailsPath: '/a/details'),
183+
routes: <RouteBase>[
184+
// The details screen to display stacked on navigator of the
185+
// first tab. This will cover screen A but not the application
186+
// shell (bottom navigation bar).
187+
GoRoute(
188+
path: 'details',
189+
builder: (BuildContext context, GoRouterState state) =>
190+
const DetailsScreen(label: 'A'),
191+
),
192+
],
193+
),
194+
],
195+
),
196+
```
197+
198+
Similar to ShellRoute, a builder must be provided to build the actual shell
199+
Widget that encapsulates the branch navigation container. The latter is
200+
implemented by the class [StatefulNavigationShell](https://pub.dev/documentation/go_router/latest/go_router/StatefulNavigationShell-class.html),
201+
which is passed as the last argument to the builder function. Example:
202+
203+
<?code-excerpt "../example/lib/stateful_shell_route.dart (configuration-builder)"?>
204+
```dart
205+
StatefulShellRoute.indexedStack(
206+
builder: (BuildContext context, GoRouterState state,
207+
StatefulNavigationShell navigationShell) {
208+
// Return the widget that implements the custom shell (in this case
209+
// using a BottomNavigationBar). The StatefulNavigationShell is passed
210+
// to be able access the state of the shell and to navigate to other
211+
// branches in a stateful way.
212+
return ScaffoldWithNavBar(navigationShell: navigationShell);
213+
},
214+
```
215+
216+
Within the custom shell widget, the StatefulNavigationShell is first and
217+
foremost used as the child, or body, of the shell. Secondly, it is also used for
218+
handling stateful switching between branches, as well as providing the currently
219+
active branch index. Example:
220+
221+
<?code-excerpt "../example/lib/stateful_shell_route.dart (configuration-custom-shell)"?>
222+
```dart
223+
@override
224+
Widget build(BuildContext context) {
225+
return Scaffold(
226+
// The StatefulNavigationShell from the associated StatefulShellRoute is
227+
// directly passed as the body of the Scaffold.
228+
body: navigationShell,
229+
bottomNavigationBar: BottomNavigationBar(
230+
// Here, the items of BottomNavigationBar are hard coded. In a real
231+
// world scenario, the items would most likely be generated from the
232+
// branches of the shell route, which can be fetched using
233+
// `navigationShell.route.branches`.
234+
items: const <BottomNavigationBarItem>[
235+
BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Section A'),
236+
BottomNavigationBarItem(icon: Icon(Icons.work), label: 'Section B'),
237+
BottomNavigationBarItem(icon: Icon(Icons.tab), label: 'Section C'),
238+
],
239+
currentIndex: navigationShell.currentIndex,
240+
// Navigate to the current location of the branch at the provided index
241+
// when tapping an item in the BottomNavigationBar.
242+
onTap: (int index) => navigationShell.goBranch(index),
243+
),
244+
);
245+
}
246+
```
247+
248+
For a complete example, see the [Stateful Nested
249+
Navigation](https://github.com/flutter/packages/blob/main/packages/go_router/example/lib/stateful_shell_route.dart)
250+
in the example/ directory.
251+
For further details, see the [StatefulShellRoute API
252+
documentation](https://pub.dev/documentation/go_router/latest/go_router/StatefulShellRoute-class.html).
253+
155254
# Initial location
156255

157256
The initial location is shown when the app first opens and there is no deep link
@@ -181,3 +280,4 @@ final _router = GoRouter(
181280
[GoRoute]: https://pub.dev/documentation/go_router/latest/go_router/GoRoute-class.html
182281
[GoRouterState]: https://pub.dev/documentation/go_router/latest/go_router/GoRouterState-class.html
183282
[ShellRoute]: https://pub.dev/documentation/go_router/latest/go_router/ShellRoute-class.html
283+
[StatefulShellRoute]: https://pub.dev/documentation/go_router/latest/go_router/StatefulShellRoute-class.html

packages/go_router/example/lib/stateful_shell_route.dart

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class NestedTabNavigationExampleApp extends StatelessWidget {
2828
navigatorKey: _rootNavigatorKey,
2929
initialLocation: '/a',
3030
routes: <RouteBase>[
31+
// #docregion configuration-builder
3132
StatefulShellRoute.indexedStack(
3233
builder: (BuildContext context, GoRouterState state,
3334
StatefulNavigationShell navigationShell) {
@@ -37,6 +38,8 @@ class NestedTabNavigationExampleApp extends StatelessWidget {
3738
// branches in a stateful way.
3839
return ScaffoldWithNavBar(navigationShell: navigationShell);
3940
},
41+
// #enddocregion configuration-builder
42+
// #docregion configuration-branches
4043
branches: <StatefulShellBranch>[
4144
// The route branch for the first tab of the bottom navigation bar.
4245
StatefulShellBranch(
@@ -61,6 +64,7 @@ class NestedTabNavigationExampleApp extends StatelessWidget {
6164
),
6265
],
6366
),
67+
// #enddocregion configuration-branches
6468

6569
// The route branch for the second tab of the bottom navigation bar.
6670
StatefulShellBranch(
@@ -145,9 +149,12 @@ class ScaffoldWithNavBar extends StatelessWidget {
145149
/// The navigation shell and container for the branch Navigators.
146150
final StatefulNavigationShell navigationShell;
147151

152+
// #docregion configuration-custom-shell
148153
@override
149154
Widget build(BuildContext context) {
150155
return Scaffold(
156+
// The StatefulNavigationShell from the associated StatefulShellRoute is
157+
// directly passed as the body of the Scaffold.
151158
body: navigationShell,
152159
bottomNavigationBar: BottomNavigationBar(
153160
// Here, the items of BottomNavigationBar are hard coded. In a real
@@ -160,13 +167,18 @@ class ScaffoldWithNavBar extends StatelessWidget {
160167
BottomNavigationBarItem(icon: Icon(Icons.tab), label: 'Section C'),
161168
],
162169
currentIndex: navigationShell.currentIndex,
163-
onTap: (int index) => _onTap(context, index),
170+
// Navigate to the current location of the branch at the provided index
171+
// when tapping an item in the BottomNavigationBar.
172+
onTap: (int index) => navigationShell.goBranch(index),
164173
),
165174
);
166175
}
176+
// #enddocregion configuration-custom-shell
167177

168-
/// Navigate to the current location of the branch at the provided index when
169-
/// tapping an item in the BottomNavigationBar.
178+
/// NOTE: For a slightly more sophisticated branch switching, change the onTap
179+
/// handler on the BottomNavigationBar above to the following:
180+
/// `onTap: (int index) => _onTap(context, index),`
181+
// ignore: unused_element
170182
void _onTap(BuildContext context, int index) {
171183
// When navigating to a new branch, it's recommended to use the goBranch
172184
// method, as doing so makes sure the last navigation state of the

packages/go_router/lib/src/route.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -777,6 +777,8 @@ class ShellRoute extends ShellRouteBase {
777777
/// * [Custom StatefulShellRoute example](https://github.com/flutter/packages/blob/main/packages/go_router/example/lib/others/custom_stateful_shell_route.dart)
778778
/// which demonstrates how to customize the container for the branch Navigators
779779
/// and how to implement animated transitions when switching branches.
780+
///
781+
/// {@category Configuration}
780782
class StatefulShellRoute extends ShellRouteBase {
781783
/// Constructs a [StatefulShellRoute] from a list of [StatefulShellBranch]es,
782784
/// each representing a separate nested navigation tree (branch).

packages/go_router/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name: go_router
22
description: A declarative router for Flutter based on Navigation 2 supporting
33
deep linking, data-driven routes and more
4-
version: 14.2.1
4+
version: 14.2.2
55
repository: https://github.com/flutter/packages/tree/main/packages/go_router
66
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+go_router%22
77

0 commit comments

Comments
 (0)