mirror of
https://github.com/flutter/flutter
synced 2024-10-13 19:52:53 +00:00
Make CupertinoTabView restorable (#67169)
This commit is contained in:
parent
4818537044
commit
582c67a125
|
@ -9,9 +9,9 @@ import 'route.dart';
|
|||
|
||||
/// A single tab view with its own [Navigator] state and history.
|
||||
///
|
||||
/// A typical tab view used as the content of each tab in a [CupertinoTabScaffold]
|
||||
/// where multiple tabs with parallel navigation states and history can
|
||||
/// co-exist.
|
||||
/// A typical tab view is used as the content of each tab in a
|
||||
/// [CupertinoTabScaffold] where multiple tabs with parallel navigation states
|
||||
/// and history can co-exist.
|
||||
///
|
||||
/// [CupertinoTabView] configures the top-level [Navigator] to search for routes
|
||||
/// in the following order:
|
||||
|
@ -49,6 +49,7 @@ class CupertinoTabView extends StatefulWidget {
|
|||
this.onGenerateRoute,
|
||||
this.onUnknownRoute,
|
||||
this.navigatorObservers = const <NavigatorObserver>[],
|
||||
this.restorationScopeId,
|
||||
}) : assert(navigatorObservers != null),
|
||||
super(key: key);
|
||||
|
||||
|
@ -125,6 +126,12 @@ class CupertinoTabView extends StatefulWidget {
|
|||
/// This list of observers is not shared with ancestor or descendant [Navigator]s.
|
||||
final List<NavigatorObserver> navigatorObservers;
|
||||
|
||||
/// Restoration ID to save and restore the state of the [Navigator] built by
|
||||
/// this [CupertinoTabView].
|
||||
///
|
||||
/// {@macro flutter.widgets.navigator.restorationScopeId}
|
||||
final String? restorationScopeId;
|
||||
|
||||
@override
|
||||
_CupertinoTabViewState createState() {
|
||||
return _CupertinoTabViewState();
|
||||
|
@ -164,6 +171,7 @@ class _CupertinoTabViewState extends State<CupertinoTabView> {
|
|||
onGenerateRoute: _onGenerateRoute,
|
||||
onUnknownRoute: _onUnknownRoute,
|
||||
observers: _navigatorObservers,
|
||||
restorationScopeId: widget.restorationScopeId,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1528,6 +1528,7 @@ class Navigator extends StatefulWidget {
|
|||
/// Restoration ID to save and restore the state of the navigator, including
|
||||
/// its history.
|
||||
///
|
||||
/// {@template flutter.widgets.navigator.restorationScopeId}
|
||||
/// If a restoration ID is provided, the navigator will persist its internal
|
||||
/// state (including the route history as well as the restorable state of the
|
||||
/// routes) and restore it during state restoration.
|
||||
|
@ -1538,11 +1539,20 @@ class Navigator extends StatefulWidget {
|
|||
///
|
||||
/// The state is persisted in a [RestorationBucket] claimed from
|
||||
/// the surrounding [RestorationScope] using the provided restoration ID.
|
||||
/// Within that bucket, the [Navigator] also creates a new [RestorationScope]
|
||||
/// for its children (the [Route]s).
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [RestorationManager], which explains how state restoration works in
|
||||
/// Flutter.
|
||||
/// * [RestorationMixin], which contains a runnable code sample showcasing
|
||||
/// state restoration in Flutter.
|
||||
/// * [Navigator], which explains under the heading "state restoration"
|
||||
/// how and under what conditions the navigator restores its state.
|
||||
/// * [Navigator.restorablePush], which includes an example showcasing how
|
||||
/// to push a restorable route unto the navigator.
|
||||
/// {@endtemplate}
|
||||
final String? restorationScopeId;
|
||||
|
||||
/// The name for the default route of the application.
|
||||
|
|
|
@ -237,4 +237,55 @@ void main() {
|
|||
' callback returned null. Such callbacks must never return null.\n'
|
||||
));
|
||||
});
|
||||
|
||||
testWidgets('Navigator of CupertinoTabView restores state', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
CupertinoApp(
|
||||
restorationScopeId: 'app',
|
||||
home: CupertinoTabView(
|
||||
restorationScopeId: 'tab',
|
||||
builder: (BuildContext context) => CupertinoButton(
|
||||
child: const Text('home'),
|
||||
onPressed: () {
|
||||
Navigator.of(context).restorablePushNamed('/2');
|
||||
},
|
||||
),
|
||||
routes: <String, WidgetBuilder>{
|
||||
'/2' : (BuildContext context) => const Text('second route'),
|
||||
}
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.text('home'), findsOneWidget);
|
||||
await tester.tap(find.text('home'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('home'), findsNothing);
|
||||
expect(find.text('second route'), findsOneWidget);
|
||||
|
||||
final TestRestorationData data = await tester.getRestorationData();
|
||||
|
||||
await tester.restartAndRestore();
|
||||
|
||||
expect(find.text('home'), findsNothing);
|
||||
expect(find.text('second route'), findsOneWidget);
|
||||
|
||||
Navigator.of(tester.element(find.text('second route'))).pop();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('home'), findsOneWidget);
|
||||
expect(find.text('second route'), findsNothing);
|
||||
|
||||
await tester.restoreFrom(data);
|
||||
|
||||
expect(find.text('home'), findsNothing);
|
||||
expect(find.text('second route'), findsOneWidget);
|
||||
|
||||
Navigator.of(tester.element(find.text('second route'))).pop();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('home'), findsOneWidget);
|
||||
expect(find.text('second route'), findsNothing);
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue