mirror of
https://github.com/flutter/packages.git
synced 2025-07-01 15:23:25 +08:00
go_router should allow setting requestFocus (#4636)
fixes: https://github.com/flutter/flutter/issues/129581
This commit is contained in:
@ -1,3 +1,7 @@
|
|||||||
|
## 10.1.0
|
||||||
|
|
||||||
|
- Supports setting `requestFocus`.
|
||||||
|
|
||||||
## 10.0.0
|
## 10.0.0
|
||||||
|
|
||||||
- **BREAKING CHANGE**:
|
- **BREAKING CHANGE**:
|
||||||
|
@ -45,6 +45,7 @@ class RouteBuilder {
|
|||||||
required this.restorationScopeId,
|
required this.restorationScopeId,
|
||||||
required this.observers,
|
required this.observers,
|
||||||
required this.onPopPageWithRouteMatch,
|
required this.onPopPageWithRouteMatch,
|
||||||
|
this.requestFocus = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// Builder function for a go router with Navigator.
|
/// Builder function for a go router with Navigator.
|
||||||
@ -63,6 +64,12 @@ class RouteBuilder {
|
|||||||
/// its history.
|
/// its history.
|
||||||
final String? restorationScopeId;
|
final String? restorationScopeId;
|
||||||
|
|
||||||
|
/// Whether or not the navigator created by this builder and it's new topmost route should request focus
|
||||||
|
/// when the new route is pushed onto the navigator.
|
||||||
|
///
|
||||||
|
/// Defaults to true.
|
||||||
|
final bool requestFocus;
|
||||||
|
|
||||||
/// NavigatorObserver used to receive notifications when navigating in between routes.
|
/// NavigatorObserver used to receive notifications when navigating in between routes.
|
||||||
/// changes.
|
/// changes.
|
||||||
final List<NavigatorObserver> observers;
|
final List<NavigatorObserver> observers;
|
||||||
@ -137,6 +144,7 @@ class RouteBuilder {
|
|||||||
navigatorKey,
|
navigatorKey,
|
||||||
observers: observers,
|
observers: observers,
|
||||||
restorationScopeId: restorationScopeId,
|
restorationScopeId: restorationScopeId,
|
||||||
|
requestFocus: requestFocus,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -258,7 +266,10 @@ class RouteBuilder {
|
|||||||
|
|
||||||
// Build the Navigator for this shell route
|
// Build the Navigator for this shell route
|
||||||
Widget buildShellNavigator(
|
Widget buildShellNavigator(
|
||||||
List<NavigatorObserver>? observers, String? restorationScopeId) {
|
List<NavigatorObserver>? observers,
|
||||||
|
String? restorationScopeId, {
|
||||||
|
bool requestFocus = true,
|
||||||
|
}) {
|
||||||
return _buildNavigator(
|
return _buildNavigator(
|
||||||
pagePopContext.onPopPage,
|
pagePopContext.onPopPage,
|
||||||
keyToPages[shellNavigatorKey]!,
|
keyToPages[shellNavigatorKey]!,
|
||||||
@ -266,6 +277,7 @@ class RouteBuilder {
|
|||||||
observers: observers ?? const <NavigatorObserver>[],
|
observers: observers ?? const <NavigatorObserver>[],
|
||||||
restorationScopeId: restorationScopeId,
|
restorationScopeId: restorationScopeId,
|
||||||
heroController: heroController,
|
heroController: heroController,
|
||||||
|
requestFocus: requestFocus,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,6 +310,7 @@ class RouteBuilder {
|
|||||||
List<NavigatorObserver> observers = const <NavigatorObserver>[],
|
List<NavigatorObserver> observers = const <NavigatorObserver>[],
|
||||||
String? restorationScopeId,
|
String? restorationScopeId,
|
||||||
HeroController? heroController,
|
HeroController? heroController,
|
||||||
|
bool requestFocus = true,
|
||||||
}) {
|
}) {
|
||||||
final Widget navigator = Navigator(
|
final Widget navigator = Navigator(
|
||||||
key: navigatorKey,
|
key: navigatorKey,
|
||||||
@ -305,6 +318,7 @@ class RouteBuilder {
|
|||||||
pages: pages,
|
pages: pages,
|
||||||
observers: observers,
|
observers: observers,
|
||||||
onPopPage: onPopPage,
|
onPopPage: onPopPage,
|
||||||
|
requestFocus: requestFocus,
|
||||||
);
|
);
|
||||||
if (heroController != null) {
|
if (heroController != null) {
|
||||||
return HeroControllerScope(
|
return HeroControllerScope(
|
||||||
|
@ -26,6 +26,7 @@ class GoRouterDelegate extends RouterDelegate<RouteMatchList>
|
|||||||
required List<NavigatorObserver> observers,
|
required List<NavigatorObserver> observers,
|
||||||
required this.routerNeglect,
|
required this.routerNeglect,
|
||||||
String? restorationScopeId,
|
String? restorationScopeId,
|
||||||
|
bool requestFocus = true,
|
||||||
}) : _configuration = configuration {
|
}) : _configuration = configuration {
|
||||||
builder = RouteBuilder(
|
builder = RouteBuilder(
|
||||||
configuration: configuration,
|
configuration: configuration,
|
||||||
@ -35,6 +36,7 @@ class GoRouterDelegate extends RouterDelegate<RouteMatchList>
|
|||||||
restorationScopeId: restorationScopeId,
|
restorationScopeId: restorationScopeId,
|
||||||
observers: observers,
|
observers: observers,
|
||||||
onPopPageWithRouteMatch: _handlePopPageWithRouteMatch,
|
onPopPageWithRouteMatch: _handlePopPageWithRouteMatch,
|
||||||
|
requestFocus: requestFocus,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,6 +49,8 @@ typedef GoExceptionHandler = void Function(
|
|||||||
/// See [Error handling](https://pub.dev/documentation/go_router/latest/topics/Error%20handling-topic.html)
|
/// See [Error handling](https://pub.dev/documentation/go_router/latest/topics/Error%20handling-topic.html)
|
||||||
/// for more details.
|
/// for more details.
|
||||||
///
|
///
|
||||||
|
/// To disable automatically requesting focus when new routes are pushed to the navigator, set `requestFocus` to false.
|
||||||
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
/// * [Configuration](https://pub.dev/documentation/go_router/latest/topics/Configuration-topic.html)
|
/// * [Configuration](https://pub.dev/documentation/go_router/latest/topics/Configuration-topic.html)
|
||||||
/// * [GoRoute], which provides APIs to define the routing table.
|
/// * [GoRoute], which provides APIs to define the routing table.
|
||||||
@ -83,6 +85,7 @@ class GoRouter implements RouterConfig<RouteMatchList> {
|
|||||||
bool debugLogDiagnostics = false,
|
bool debugLogDiagnostics = false,
|
||||||
GlobalKey<NavigatorState>? navigatorKey,
|
GlobalKey<NavigatorState>? navigatorKey,
|
||||||
String? restorationScopeId,
|
String? restorationScopeId,
|
||||||
|
bool requestFocus = true,
|
||||||
}) : backButtonDispatcher = RootBackButtonDispatcher(),
|
}) : backButtonDispatcher = RootBackButtonDispatcher(),
|
||||||
assert(
|
assert(
|
||||||
initialExtra == null || initialLocation != null,
|
initialExtra == null || initialLocation != null,
|
||||||
@ -147,6 +150,7 @@ class GoRouter implements RouterConfig<RouteMatchList> {
|
|||||||
...observers ?? <NavigatorObserver>[],
|
...observers ?? <NavigatorObserver>[],
|
||||||
],
|
],
|
||||||
restorationScopeId: restorationScopeId,
|
restorationScopeId: restorationScopeId,
|
||||||
|
requestFocus: requestFocus,
|
||||||
// wrap the returned Navigator to enable GoRouter.of(context).go() et al,
|
// wrap the returned Navigator to enable GoRouter.of(context).go() et al,
|
||||||
// allowing the caller to wrap the navigator themselves
|
// allowing the caller to wrap the navigator themselves
|
||||||
builderWithNav: (BuildContext context, Widget child) =>
|
builderWithNav: (BuildContext context, Widget child) =>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
name: go_router
|
name: go_router
|
||||||
description: A declarative router for Flutter based on Navigation 2 supporting
|
description: A declarative router for Flutter based on Navigation 2 supporting
|
||||||
deep linking, data-driven routes and more
|
deep linking, data-driven routes and more
|
||||||
version: 10.0.0
|
version: 10.1.0
|
||||||
repository: https://github.com/flutter/packages/tree/main/packages/go_router
|
repository: https://github.com/flutter/packages/tree/main/packages/go_router
|
||||||
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+go_router%22
|
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+go_router%22
|
||||||
|
|
||||||
|
61
packages/go_router/test/request_focus.dart
Normal file
61
packages/go_router/test/request_focus.dart
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets('GoRouter does not request focus if requestFocus is false',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final GlobalKey innerKey = GlobalKey();
|
||||||
|
final FocusScopeNode focusNode = FocusScopeNode();
|
||||||
|
final GoRouter router = GoRouter(
|
||||||
|
initialLocation: '/',
|
||||||
|
routes: <GoRoute>[
|
||||||
|
GoRoute(
|
||||||
|
path: '/',
|
||||||
|
name: 'home',
|
||||||
|
builder: (_, __) => const Text('A'),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/second',
|
||||||
|
name: 'second',
|
||||||
|
builder: (_, __) => Text('B', key: innerKey),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
requestFocus: false,
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpWidget(Column(
|
||||||
|
children: <Widget>[
|
||||||
|
FocusScope(node: focusNode, child: Container()),
|
||||||
|
Expanded(
|
||||||
|
child: MaterialApp.router(
|
||||||
|
routerConfig: router,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(find.text('A'), findsOneWidget);
|
||||||
|
expect(find.text('B', skipOffstage: false), findsNothing);
|
||||||
|
expect(focusNode.hasFocus, false);
|
||||||
|
focusNode.requestFocus();
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(focusNode.hasFocus, true);
|
||||||
|
|
||||||
|
router.pushNamed('second');
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(find.text('A', skipOffstage: false), findsOneWidget);
|
||||||
|
expect(find.text('B'), findsOneWidget);
|
||||||
|
expect(focusNode.hasFocus, true);
|
||||||
|
|
||||||
|
router.pop();
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(find.text('A'), findsOneWidget);
|
||||||
|
expect(find.text('B', skipOffstage: false), findsNothing);
|
||||||
|
expect(focusNode.hasFocus, true);
|
||||||
|
});
|
||||||
|
}
|
@ -149,6 +149,7 @@ Future<GoRouter> createRouter(
|
|||||||
GoRouterWidgetBuilder? errorBuilder,
|
GoRouterWidgetBuilder? errorBuilder,
|
||||||
String? restorationScopeId,
|
String? restorationScopeId,
|
||||||
GoExceptionHandler? onException,
|
GoExceptionHandler? onException,
|
||||||
|
bool requestFocus = true,
|
||||||
}) async {
|
}) async {
|
||||||
final GoRouter goRouter = GoRouter(
|
final GoRouter goRouter = GoRouter(
|
||||||
routes: routes,
|
routes: routes,
|
||||||
@ -160,6 +161,7 @@ Future<GoRouter> createRouter(
|
|||||||
errorBuilder: errorBuilder,
|
errorBuilder: errorBuilder,
|
||||||
navigatorKey: navigatorKey,
|
navigatorKey: navigatorKey,
|
||||||
restorationScopeId: restorationScopeId,
|
restorationScopeId: restorationScopeId,
|
||||||
|
requestFocus: requestFocus,
|
||||||
);
|
);
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp.router(
|
MaterialApp.router(
|
||||||
|
Reference in New Issue
Block a user