diff --git a/packages/flutter/lib/src/widgets/navigator.dart b/packages/flutter/lib/src/widgets/navigator.dart index 20e3556a9fd..3abfb7083ad 100644 --- a/packages/flutter/lib/src/widgets/navigator.dart +++ b/packages/flutter/lib/src/widgets/navigator.dart @@ -1616,7 +1616,7 @@ class Navigator extends StatefulWidget { /// ``` /// {@end-tool} @optionalTypeArgs - static Future pushNamed( + static Future pushNamed( BuildContext context, String routeName, { Object? arguments, @@ -1673,7 +1673,7 @@ class Navigator extends StatefulWidget { /// ``` /// {@end-tool} @optionalTypeArgs - static Future pushReplacementNamed( + static Future pushReplacementNamed( BuildContext context, String routeName, { TO? result, @@ -1726,7 +1726,7 @@ class Navigator extends StatefulWidget { /// ``` /// {@end-tool} @optionalTypeArgs - static Future popAndPushNamed( + static Future popAndPushNamed( BuildContext context, String routeName, { TO? result, @@ -1790,7 +1790,7 @@ class Navigator extends StatefulWidget { /// ``` /// {@end-tool} @optionalTypeArgs - static Future pushNamedAndRemoveUntil( + static Future pushNamedAndRemoveUntil( BuildContext context, String newRouteName, RoutePredicate predicate, { @@ -1828,7 +1828,7 @@ class Navigator extends StatefulWidget { /// ``` /// {@end-tool} @optionalTypeArgs - static Future push(BuildContext context, Route route) { + static Future push(BuildContext context, Route route) { return Navigator.of(context)!.push(route); } @@ -1872,7 +1872,7 @@ class Navigator extends StatefulWidget { /// ``` /// {@end-tool} @optionalTypeArgs - static Future pushReplacement(BuildContext context, Route newRoute, { TO? result }) { + static Future pushReplacement(BuildContext context, Route newRoute, { TO? result }) { return Navigator.of(context)!.pushReplacement(newRoute, result: result); } @@ -1926,7 +1926,7 @@ class Navigator extends StatefulWidget { /// ``` /// {@end-tool} @optionalTypeArgs - static Future pushAndRemoveUntil(BuildContext context, Route newRoute, RoutePredicate predicate) { + static Future pushAndRemoveUntil(BuildContext context, Route newRoute, RoutePredicate predicate) { return Navigator.of(context)!.pushAndRemoveUntil(newRoute, predicate); } @@ -1962,7 +1962,7 @@ class Navigator extends StatefulWidget { /// * [replaceRouteBelow], which is the same but identifies the route to be /// removed by reference to the route above it, rather than directly. @optionalTypeArgs - static void replace(BuildContext context, { required Route oldRoute, required Route newRoute }) { + static void replace(BuildContext context, { required Route oldRoute, required Route newRoute }) { return Navigator.of(context)!.replace(oldRoute: oldRoute, newRoute: newRoute); } @@ -1996,7 +1996,7 @@ class Navigator extends StatefulWidget { /// * [replace], which is the same but identifies the route to be removed /// directly. @optionalTypeArgs - static void replaceRouteBelow(BuildContext context, { required Route anchorRoute, required Route newRoute }) { + static void replaceRouteBelow(BuildContext context, { required Route anchorRoute, required Route newRoute }) { return Navigator.of(context)!.replaceRouteBelow(anchorRoute: anchorRoute, newRoute: newRoute); } @@ -2051,7 +2051,7 @@ class Navigator extends StatefulWidget { /// * [ModalRoute], which provides a `scopedWillPopCallback` that can be used /// to define the route's `willPop` method. @optionalTypeArgs - static Future maybePop(BuildContext context, [ T? result ]) { + static Future maybePop(BuildContext context, [ T? result ]) { return Navigator.of(context)!.maybePop(result); } @@ -2101,7 +2101,7 @@ class Navigator extends StatefulWidget { /// } /// ``` @optionalTypeArgs - static void pop(BuildContext context, [ T? result ]) { + static void pop(BuildContext context, [ T? result ]) { Navigator.of(context)!.pop(result); } @@ -3456,7 +3456,7 @@ class NavigatorState extends State with TickerProviderStateMixin { /// ``` /// {@end-tool} @optionalTypeArgs - Future pushNamed( + Future pushNamed( String routeName, { Object? arguments, }) { @@ -3482,7 +3482,7 @@ class NavigatorState extends State with TickerProviderStateMixin { /// ``` /// {@end-tool} @optionalTypeArgs - Future pushReplacementNamed( + Future pushReplacementNamed( String routeName, { TO? result, Object? arguments, @@ -3508,7 +3508,7 @@ class NavigatorState extends State with TickerProviderStateMixin { /// ``` /// {@end-tool} @optionalTypeArgs - Future popAndPushNamed( + Future popAndPushNamed( String routeName, { TO? result, Object? arguments, @@ -3535,7 +3535,7 @@ class NavigatorState extends State with TickerProviderStateMixin { /// ``` /// {@end-tool} @optionalTypeArgs - Future pushNamedAndRemoveUntil( + Future pushNamedAndRemoveUntil( String newRouteName, RoutePredicate predicate, { Object? arguments, @@ -3633,7 +3633,7 @@ class NavigatorState extends State with TickerProviderStateMixin { /// ``` /// {@end-tool} @optionalTypeArgs - Future pushReplacement(Route newRoute, { TO? result }) { + Future pushReplacement(Route newRoute, { TO? result }) { assert(!_debugLocked); assert(() { _debugLocked = true; @@ -3673,7 +3673,7 @@ class NavigatorState extends State with TickerProviderStateMixin { /// ``` /// {@end-tool} @optionalTypeArgs - Future pushAndRemoveUntil(Route newRoute, RoutePredicate predicate) { + Future pushAndRemoveUntil(Route newRoute, RoutePredicate predicate) { assert(!_debugLocked); assert(() { _debugLocked = true; @@ -3709,7 +3709,7 @@ class NavigatorState extends State with TickerProviderStateMixin { /// * [replaceRouteBelow], which is the same but identifies the route to be /// removed by reference to the route above it, rather than directly. @optionalTypeArgs - void replace({ required Route oldRoute, required Route newRoute }) { + void replace({ required Route oldRoute, required Route newRoute }) { assert(!_debugLocked); assert(oldRoute != null); assert(newRoute != null); @@ -3746,7 +3746,7 @@ class NavigatorState extends State with TickerProviderStateMixin { /// * [replace], which is the same but identifies the route to be removed /// directly. @optionalTypeArgs - void replaceRouteBelow({ required Route anchorRoute, required Route newRoute }) { + void replaceRouteBelow({ required Route anchorRoute, required Route newRoute }) { assert(!_debugLocked); assert(() { _debugLocked = true; return true; }()); assert(anchorRoute != null); @@ -3800,7 +3800,8 @@ class NavigatorState extends State with TickerProviderStateMixin { /// to veto a [pop] initiated by the app's back button. /// * [ModalRoute], which provides a `scopedWillPopCallback` that can be used /// to define the route's `willPop` method. - Future maybePop([ T? result ]) async { + @optionalTypeArgs + Future maybePop([ T? result ]) async { final _RouteEntry? lastEntry = _history.cast<_RouteEntry?>().lastWhere( (_RouteEntry? e) => e != null && _RouteEntry.isPresentPredicate(e), orElse: () => null, @@ -3854,7 +3855,7 @@ class NavigatorState extends State with TickerProviderStateMixin { /// ``` /// {@end-tool} @optionalTypeArgs - void pop([ T? result ]) { + void pop([ T? result ]) { assert(!_debugLocked); assert(() { _debugLocked = true; diff --git a/packages/flutter/test/widgets/navigator_test.dart b/packages/flutter/test/widgets/navigator_test.dart index fb11e72893e..d2870e6b006 100644 --- a/packages/flutter/test/widgets/navigator_test.dart +++ b/packages/flutter/test/widgets/navigator_test.dart @@ -343,6 +343,33 @@ void main() { expect(find.text('B'), findsOneWidget); }); + testWidgets('popAndPushNamed with explicit void type parameter', (WidgetTester tester) async { + final Map routes = { + '/' : (BuildContext context) => OnTapPage(id: '/', onTap: () { Navigator.pushNamed(context, '/A'); }), + '/A': (BuildContext context) => OnTapPage(id: 'A', onTap: () { Navigator.popAndPushNamed(context, '/B'); }), + '/B': (BuildContext context) => OnTapPage(id: 'B', onTap: () { Navigator.pop(context); }), + }; + + await tester.pumpWidget(MaterialApp(routes: routes)); + expect(find.text('/'), findsOneWidget); + expect(find.text('A', skipOffstage: false), findsNothing); + expect(find.text('B', skipOffstage: false), findsNothing); + + await tester.tap(find.text('/')); + await tester.pump(); + await tester.pump(const Duration(seconds: 1)); + expect(find.text('/'), findsNothing); + expect(find.text('A'), findsOneWidget); + expect(find.text('B'), findsNothing); + + await tester.tap(find.text('A')); + await tester.pump(); + await tester.pump(const Duration(seconds: 1)); + expect(find.text('/'), findsNothing); + expect(find.text('A'), findsNothing); + expect(find.text('B'), findsOneWidget); + }); + testWidgets('Push and pop should trigger the observers', (WidgetTester tester) async { final Map routes = { '/' : (BuildContext context) => OnTapPage(id: '/', onTap: () { Navigator.pushNamed(context, '/A'); }),