Skip to content

Commit 4ff585e

Browse files
authored
go_router should allow setting requestFocus (flutter#4636)
fixes: flutter#129581
1 parent 175ff56 commit 4ff585e

File tree

7 files changed

+89
-2
lines changed

7 files changed

+89
-2
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+
## 10.1.0
2+
3+
- Supports setting `requestFocus`.
4+
15
## 10.0.0
26

37
- **BREAKING CHANGE**:

packages/go_router/lib/src/builder.dart

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class RouteBuilder {
4545
required this.restorationScopeId,
4646
required this.observers,
4747
required this.onPopPageWithRouteMatch,
48+
this.requestFocus = true,
4849
});
4950

5051
/// Builder function for a go router with Navigator.
@@ -63,6 +64,12 @@ class RouteBuilder {
6364
/// its history.
6465
final String? restorationScopeId;
6566

67+
/// Whether or not the navigator created by this builder and it's new topmost route should request focus
68+
/// when the new route is pushed onto the navigator.
69+
///
70+
/// Defaults to true.
71+
final bool requestFocus;
72+
6673
/// NavigatorObserver used to receive notifications when navigating in between routes.
6774
/// changes.
6875
final List<NavigatorObserver> observers;
@@ -137,6 +144,7 @@ class RouteBuilder {
137144
navigatorKey,
138145
observers: observers,
139146
restorationScopeId: restorationScopeId,
147+
requestFocus: requestFocus,
140148
),
141149
);
142150
}
@@ -258,14 +266,18 @@ class RouteBuilder {
258266

259267
// Build the Navigator for this shell route
260268
Widget buildShellNavigator(
261-
List<NavigatorObserver>? observers, String? restorationScopeId) {
269+
List<NavigatorObserver>? observers,
270+
String? restorationScopeId, {
271+
bool requestFocus = true,
272+
}) {
262273
return _buildNavigator(
263274
pagePopContext.onPopPage,
264275
keyToPages[shellNavigatorKey]!,
265276
shellNavigatorKey,
266277
observers: observers ?? const <NavigatorObserver>[],
267278
restorationScopeId: restorationScopeId,
268279
heroController: heroController,
280+
requestFocus: requestFocus,
269281
);
270282
}
271283

@@ -298,13 +310,15 @@ class RouteBuilder {
298310
List<NavigatorObserver> observers = const <NavigatorObserver>[],
299311
String? restorationScopeId,
300312
HeroController? heroController,
313+
bool requestFocus = true,
301314
}) {
302315
final Widget navigator = Navigator(
303316
key: navigatorKey,
304317
restorationScopeId: restorationScopeId,
305318
pages: pages,
306319
observers: observers,
307320
onPopPage: onPopPage,
321+
requestFocus: requestFocus,
308322
);
309323
if (heroController != null) {
310324
return HeroControllerScope(

packages/go_router/lib/src/delegate.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class GoRouterDelegate extends RouterDelegate<RouteMatchList>
2626
required List<NavigatorObserver> observers,
2727
required this.routerNeglect,
2828
String? restorationScopeId,
29+
bool requestFocus = true,
2930
}) : _configuration = configuration {
3031
builder = RouteBuilder(
3132
configuration: configuration,
@@ -35,6 +36,7 @@ class GoRouterDelegate extends RouterDelegate<RouteMatchList>
3536
restorationScopeId: restorationScopeId,
3637
observers: observers,
3738
onPopPageWithRouteMatch: _handlePopPageWithRouteMatch,
39+
requestFocus: requestFocus,
3840
);
3941
}
4042

packages/go_router/lib/src/router.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ typedef GoExceptionHandler = void Function(
4949
/// See [Error handling](https://pub.dev/documentation/go_router/latest/topics/Error%20handling-topic.html)
5050
/// for more details.
5151
///
52+
/// To disable automatically requesting focus when new routes are pushed to the navigator, set `requestFocus` to false.
53+
///
5254
/// See also:
5355
/// * [Configuration](https://pub.dev/documentation/go_router/latest/topics/Configuration-topic.html)
5456
/// * [GoRoute], which provides APIs to define the routing table.
@@ -83,6 +85,7 @@ class GoRouter implements RouterConfig<RouteMatchList> {
8385
bool debugLogDiagnostics = false,
8486
GlobalKey<NavigatorState>? navigatorKey,
8587
String? restorationScopeId,
88+
bool requestFocus = true,
8689
}) : backButtonDispatcher = RootBackButtonDispatcher(),
8790
assert(
8891
initialExtra == null || initialLocation != null,
@@ -147,6 +150,7 @@ class GoRouter implements RouterConfig<RouteMatchList> {
147150
...observers ?? <NavigatorObserver>[],
148151
],
149152
restorationScopeId: restorationScopeId,
153+
requestFocus: requestFocus,
150154
// wrap the returned Navigator to enable GoRouter.of(context).go() et al,
151155
// allowing the caller to wrap the navigator themselves
152156
builderWithNav: (BuildContext context, Widget child) =>

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: 10.0.0
4+
version: 10.1.0
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

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:flutter/material.dart';
6+
import 'package:flutter_test/flutter_test.dart';
7+
import 'package:go_router/go_router.dart';
8+
9+
void main() {
10+
testWidgets('GoRouter does not request focus if requestFocus is false',
11+
(WidgetTester tester) async {
12+
final GlobalKey innerKey = GlobalKey();
13+
final FocusScopeNode focusNode = FocusScopeNode();
14+
final GoRouter router = GoRouter(
15+
initialLocation: '/',
16+
routes: <GoRoute>[
17+
GoRoute(
18+
path: '/',
19+
name: 'home',
20+
builder: (_, __) => const Text('A'),
21+
),
22+
GoRoute(
23+
path: '/second',
24+
name: 'second',
25+
builder: (_, __) => Text('B', key: innerKey),
26+
),
27+
],
28+
requestFocus: false,
29+
);
30+
31+
await tester.pumpWidget(Column(
32+
children: <Widget>[
33+
FocusScope(node: focusNode, child: Container()),
34+
Expanded(
35+
child: MaterialApp.router(
36+
routerConfig: router,
37+
),
38+
),
39+
],
40+
));
41+
42+
expect(find.text('A'), findsOneWidget);
43+
expect(find.text('B', skipOffstage: false), findsNothing);
44+
expect(focusNode.hasFocus, false);
45+
focusNode.requestFocus();
46+
await tester.pumpAndSettle();
47+
expect(focusNode.hasFocus, true);
48+
49+
router.pushNamed('second');
50+
await tester.pumpAndSettle();
51+
expect(find.text('A', skipOffstage: false), findsOneWidget);
52+
expect(find.text('B'), findsOneWidget);
53+
expect(focusNode.hasFocus, true);
54+
55+
router.pop();
56+
await tester.pumpAndSettle();
57+
expect(find.text('A'), findsOneWidget);
58+
expect(find.text('B', skipOffstage: false), findsNothing);
59+
expect(focusNode.hasFocus, true);
60+
});
61+
}

packages/go_router/test/test_helpers.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ Future<GoRouter> createRouter(
149149
GoRouterWidgetBuilder? errorBuilder,
150150
String? restorationScopeId,
151151
GoExceptionHandler? onException,
152+
bool requestFocus = true,
152153
}) async {
153154
final GoRouter goRouter = GoRouter(
154155
routes: routes,
@@ -160,6 +161,7 @@ Future<GoRouter> createRouter(
160161
errorBuilder: errorBuilder,
161162
navigatorKey: navigatorKey,
162163
restorationScopeId: restorationScopeId,
164+
requestFocus: requestFocus,
163165
);
164166
await tester.pumpWidget(
165167
MaterialApp.router(

0 commit comments

Comments
 (0)