Add navigatorKey to CupertinoTabView (#25183)
diff --git a/packages/flutter/lib/src/cupertino/tab_view.dart b/packages/flutter/lib/src/cupertino/tab_view.dart
index 08bb615..03746ff 100644
--- a/packages/flutter/lib/src/cupertino/tab_view.dart
+++ b/packages/flutter/lib/src/cupertino/tab_view.dart
@@ -43,6 +43,7 @@
const CupertinoTabView({
Key key,
this.builder,
+ this.navigatorKey,
this.defaultTitle,
this.routes,
this.onGenerateRoute,
@@ -58,6 +59,19 @@
/// as [builder] takes its place.
final WidgetBuilder builder;
+ /// A key to use when building this widget's [Navigator].
+ ///
+ /// If a [navigatorKey] is specified, the [Navigator] can be directly
+ /// manipulated without first obtaining it from a [BuildContext] via
+ /// [Navigator.of]: from the [navigatorKey], use the [GlobalKey.currentState]
+ /// getter.
+ ///
+ /// If this is changed, a new [Navigator] will be created, losing all the
+ /// tab's state in the process; in that case, the [navigatorObservers]
+ /// must also be changed, since the previous observers will be attached to the
+ /// previous navigator.
+ final GlobalKey<NavigatorState> navigatorKey;
+
/// The title of the default route.
final String defaultTitle;
@@ -120,9 +134,12 @@
}
@override
- void didUpdateWidget(CupertinoTabView oldWidget) {
- super.didUpdateWidget(oldWidget);
- _updateObservers();
+ void didUpdateWidget(CupertinoTabView oldWidget) {
+ super.didUpdateWidget(oldWidget);
+ if (widget.navigatorKey != oldWidget.navigatorKey
+ || widget.navigatorObservers != oldWidget.navigatorObservers) {
+ _updateObservers();
+ }
}
void _updateObservers() {
@@ -134,6 +151,7 @@
@override
Widget build(BuildContext context) {
return Navigator(
+ key: widget.navigatorKey,
onGenerateRoute: _onGenerateRoute,
onUnknownRoute: _onUnknownRoute,
observers: _navigatorObservers,
diff --git a/packages/flutter/test/cupertino/tab_test.dart b/packages/flutter/test/cupertino/tab_test.dart
index 08a873e..ce17615 100644
--- a/packages/flutter/test/cupertino/tab_test.dart
+++ b/packages/flutter/test/cupertino/tab_test.dart
@@ -96,4 +96,75 @@
expect(tester.takeException(), isFlutterError);
expect(unknownForRouteCalled, '/');
});
+
+ testWidgets('Can use navigatorKey to navigate', (WidgetTester tester) async {
+ final GlobalKey<NavigatorState> key = GlobalKey();
+ await tester.pumpWidget(
+ CupertinoApp(
+ home: CupertinoTabView(
+ navigatorKey: key,
+ builder: (BuildContext context) => const Text('first route'),
+ routes: <String, WidgetBuilder>{
+ '/2': (BuildContext context) => const Text('second route'),
+ },
+ ),
+ ),
+ );
+
+ key.currentState.pushNamed('/2');
+
+ await tester.pump();
+ await tester.pump(const Duration(milliseconds: 300));
+ expect(find.text('second route'), findsOneWidget);
+ });
+
+ testWidgets('Changing the key resets the navigator', (WidgetTester tester) async {
+ final GlobalKey<NavigatorState> key = GlobalKey();
+ await tester.pumpWidget(
+ CupertinoApp(
+ home: CupertinoTabView(
+ builder: (BuildContext context) {
+ return CupertinoButton(
+ child: const Text('go to second page'),
+ onPressed: () {
+ Navigator.of(context).pushNamed('/2');
+ },
+ );
+ },
+ routes: <String, WidgetBuilder>{
+ '/2': (BuildContext context) => const Text('second route'),
+ },
+ ),
+ ),
+ );
+
+ expect(find.text('go to second page'), findsOneWidget);
+ await tester.tap(find.text('go to second page'));
+ await tester.pump();
+ await tester.pump(const Duration(milliseconds: 300));
+ expect(find.text('second route'), findsOneWidget);
+
+ await tester.pumpWidget(
+ CupertinoApp(
+ home: CupertinoTabView(
+ key: key,
+ builder: (BuildContext context) {
+ return CupertinoButton(
+ child: const Text('go to second page'),
+ onPressed: () {
+ Navigator.of(context).pushNamed('/2');
+ },
+ );
+ },
+ routes: <String, WidgetBuilder>{
+ '/2': (BuildContext context) => const Text('second route'),
+ },
+ ),
+ ),
+ );
+
+ // The stack is gone and we're back to a re-built page 1.
+ expect(find.text('go to second page'), findsOneWidget);
+ expect(find.text('second route'), findsNothing);
+ });
}