mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Support custom transition duration for DialogRoute
, CupertinoDialogRoute
and show dialog methods. (#154048)
Currently we don't support custom transition duration for `DialogRoute`, `CupertinoDialogRoute` and show dialog methods , This PR will to support that.
This commit is contained in:
parent
d9321159bf
commit
0eaeb0d1c5
@ -57,6 +57,9 @@ const Color kCupertinoModalBarrierColor = CupertinoDynamicColor.withBrightness(
|
||||
// The duration of the transition used when a modal popup is shown.
|
||||
const Duration _kModalPopupTransitionDuration = Duration(milliseconds: 335);
|
||||
|
||||
// The transition duration used for [CupertinoDialogRoute] transitions.
|
||||
const Duration _kCupertinoDialogRouteTransitionDuration = Duration(milliseconds: 250);
|
||||
|
||||
// Offset from offscreen to the right to fully on screen.
|
||||
final Animatable<Offset> _kRightMiddleTween = Tween<Offset>(
|
||||
begin: const Offset(1.0, 0.0),
|
||||
@ -1269,6 +1272,10 @@ Widget _buildCupertinoDialogTransitions(BuildContext context, Animation<double>
|
||||
/// By default, `useRootNavigator` is `true` and the dialog route created by
|
||||
/// this method is pushed to the root navigator.
|
||||
///
|
||||
/// the `transitionDuration` argument is used to specify the duration of
|
||||
/// the dialog's entrance and exit animations. If it's not provided or `null`,
|
||||
/// then it uses the default value as set by [CupertinoDialogRoute].
|
||||
///
|
||||
/// {@macro flutter.widgets.RawDialogRoute}
|
||||
///
|
||||
/// If the application has multiple [Navigator] objects, it may be necessary to
|
||||
@ -1313,6 +1320,7 @@ Future<T?> showCupertinoDialog<T>({
|
||||
bool barrierDismissible = false,
|
||||
RouteSettings? routeSettings,
|
||||
Offset? anchorPoint,
|
||||
Duration? transitionDuration,
|
||||
}) {
|
||||
|
||||
return Navigator.of(context, rootNavigator: useRootNavigator).push<T>(CupertinoDialogRoute<T>(
|
||||
@ -1323,6 +1331,7 @@ Future<T?> showCupertinoDialog<T>({
|
||||
barrierColor: CupertinoDynamicColor.resolve(kCupertinoModalBarrierColor, context),
|
||||
settings: routeSettings,
|
||||
anchorPoint: anchorPoint,
|
||||
transitionDuration: transitionDuration,
|
||||
));
|
||||
}
|
||||
|
||||
@ -1350,6 +1359,10 @@ Future<T?> showCupertinoDialog<T>({
|
||||
/// barrier that darkens everything below the dialog. If `null`, then
|
||||
/// [CupertinoDynamicColor.resolve] is used to compute the modal color.
|
||||
///
|
||||
/// The `transitionDuration` argument is used to specify the duration of
|
||||
/// the dialog's entrance and exit animations. If it's not provided or `null`,
|
||||
/// then the default duration `Duration(milliseconds: 250)` is used.
|
||||
///
|
||||
/// The `settings` argument define the settings for this route. See
|
||||
/// [RouteSettings] for details.
|
||||
///
|
||||
@ -1372,7 +1385,7 @@ class CupertinoDialogRoute<T> extends RawDialogRoute<T> {
|
||||
Color? barrierColor,
|
||||
String? barrierLabel,
|
||||
// This transition duration was eyeballed comparing with iOS
|
||||
super.transitionDuration = const Duration(milliseconds: 250),
|
||||
Duration? transitionDuration,
|
||||
this.transitionBuilder,
|
||||
super.settings,
|
||||
super.requestFocus,
|
||||
@ -1384,6 +1397,7 @@ class CupertinoDialogRoute<T> extends RawDialogRoute<T> {
|
||||
transitionBuilder: transitionBuilder ?? _buildCupertinoDialogTransitions,
|
||||
barrierLabel: barrierLabel ?? CupertinoLocalizations.of(context).modalBarrierDismissLabel,
|
||||
barrierColor: barrierColor ?? CupertinoDynamicColor.resolve(kCupertinoModalBarrierColor, context),
|
||||
transitionDuration: transitionDuration ?? _kCupertinoDialogRouteTransitionDuration,
|
||||
);
|
||||
|
||||
/// Custom transition builder
|
||||
|
@ -31,6 +31,9 @@ import 'theme_data.dart';
|
||||
|
||||
const EdgeInsets _defaultInsetPadding = EdgeInsets.symmetric(horizontal: 40.0, vertical: 24.0);
|
||||
|
||||
// The transition duration used for [DialogRoute] transitions.
|
||||
const Duration _kDialogRouteTransitionDuration = Duration(milliseconds: 150);
|
||||
|
||||
/// A Material Design dialog.
|
||||
///
|
||||
/// This dialog widget does not have any opinion about the contents of the
|
||||
@ -1345,6 +1348,10 @@ Widget _buildMaterialDialogTransitions(BuildContext context, Animation<double> a
|
||||
/// field from `DialogThemeData` is used. If that is `null` the default color
|
||||
/// `Colors.black54` is used.
|
||||
///
|
||||
/// the `transitionDuration` argument is used to specify the duration of
|
||||
/// the dialog's entrance and exit animations. If it's not provided or `null`,
|
||||
/// then it uses the default value as set by [DialogRoute].
|
||||
///
|
||||
/// The `useSafeArea` argument is used to indicate if the dialog should only
|
||||
/// display in 'safe' areas of the screen not used by the operating system
|
||||
/// (see [SafeArea] for more details). It is `true` by default, which means
|
||||
@ -1428,6 +1435,7 @@ Future<T?> showDialog<T>({
|
||||
RouteSettings? routeSettings,
|
||||
Offset? anchorPoint,
|
||||
TraversalEdgeBehavior? traversalEdgeBehavior,
|
||||
Duration? transitionDuration,
|
||||
}) {
|
||||
assert(_debugIsActive(context));
|
||||
assert(debugCheckHasMaterialLocalizations(context));
|
||||
@ -1454,6 +1462,7 @@ Future<T?> showDialog<T>({
|
||||
themes: themes,
|
||||
anchorPoint: anchorPoint,
|
||||
traversalEdgeBehavior: traversalEdgeBehavior ?? TraversalEdgeBehavior.closedLoop,
|
||||
transitionDuration: transitionDuration,
|
||||
));
|
||||
}
|
||||
|
||||
@ -1465,6 +1474,10 @@ Future<T?> showDialog<T>({
|
||||
///
|
||||
/// On Cupertino platforms, [barrierColor], [useSafeArea], and
|
||||
/// [traversalEdgeBehavior] are ignored.
|
||||
///
|
||||
/// The `transitionDuration` argument is used to specify the duration of
|
||||
/// the dialog's entrance and exit animations. If it's not provided or `null`,
|
||||
/// then it uses the default value as set by [DialogRoute] or [CupertinoDialogRoute].
|
||||
Future<T?> showAdaptiveDialog<T>({
|
||||
required BuildContext context,
|
||||
required WidgetBuilder builder,
|
||||
@ -1476,6 +1489,7 @@ Future<T?> showAdaptiveDialog<T>({
|
||||
RouteSettings? routeSettings,
|
||||
Offset? anchorPoint,
|
||||
TraversalEdgeBehavior? traversalEdgeBehavior,
|
||||
Duration? transitionDuration,
|
||||
}) {
|
||||
final ThemeData theme = Theme.of(context);
|
||||
switch (theme.platform) {
|
||||
@ -1494,6 +1508,7 @@ Future<T?> showAdaptiveDialog<T>({
|
||||
routeSettings: routeSettings,
|
||||
anchorPoint: anchorPoint,
|
||||
traversalEdgeBehavior: traversalEdgeBehavior,
|
||||
transitionDuration: transitionDuration,
|
||||
);
|
||||
case TargetPlatform.iOS:
|
||||
case TargetPlatform.macOS:
|
||||
@ -1505,6 +1520,7 @@ Future<T?> showAdaptiveDialog<T>({
|
||||
useRootNavigator: useRootNavigator,
|
||||
anchorPoint: anchorPoint,
|
||||
routeSettings: routeSettings,
|
||||
transitionDuration: transitionDuration,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1552,6 +1568,10 @@ bool _debugIsActive(BuildContext context) {
|
||||
/// barrier that darkens everything below the dialog. If `null`, the default
|
||||
/// color `Colors.black54` is used.
|
||||
///
|
||||
/// the `transitionDuration` argument is used to specify the duration of
|
||||
/// the dialog's entrance and exit animations. If it's not provided or `null`,
|
||||
/// then the default duration `Duration(milliseconds: 150)` is used.
|
||||
///
|
||||
/// The `useSafeArea` argument is used to indicate if the dialog should only
|
||||
/// display in 'safe' areas of the screen not used by the operating system
|
||||
/// (see [SafeArea] for more details). It is `true` by default, which means
|
||||
@ -1582,6 +1602,7 @@ class DialogRoute<T> extends RawDialogRoute<T> {
|
||||
super.barrierDismissible,
|
||||
String? barrierLabel,
|
||||
bool useSafeArea = true,
|
||||
Duration? transitionDuration,
|
||||
super.settings,
|
||||
super.requestFocus,
|
||||
super.anchorPoint,
|
||||
@ -1596,8 +1617,8 @@ class DialogRoute<T> extends RawDialogRoute<T> {
|
||||
return dialog;
|
||||
},
|
||||
barrierLabel: barrierLabel ?? MaterialLocalizations.of(context).modalBarrierDismissLabel,
|
||||
transitionDuration: const Duration(milliseconds: 150),
|
||||
transitionBuilder: _buildMaterialDialogTransitions,
|
||||
transitionDuration: transitionDuration ?? _kDialogRouteTransitionDuration,
|
||||
);
|
||||
|
||||
CurvedAnimation? _curvedAnimation;
|
||||
|
@ -1883,6 +1883,45 @@ void main() {
|
||||
expect(nestedObserver.dialogCount, 0);
|
||||
});
|
||||
|
||||
testWidgets('showCupertinoDialog - custom transitionDuration', (WidgetTester tester) async {
|
||||
final DialogObserver rootObserver = DialogObserver();
|
||||
final DialogObserver nestedObserver = DialogObserver();
|
||||
|
||||
await tester.pumpWidget(CupertinoApp(
|
||||
navigatorObservers: <NavigatorObserver>[rootObserver],
|
||||
home: Navigator(
|
||||
observers: <NavigatorObserver>[nestedObserver],
|
||||
onGenerateRoute: (RouteSettings settings) {
|
||||
return PageRouteBuilder<dynamic>(
|
||||
pageBuilder: (BuildContext context, Animation<double> _, Animation<double> __) {
|
||||
return GestureDetector(
|
||||
onTap: () async {
|
||||
await showCupertinoDialog<void>(
|
||||
context: context,
|
||||
transitionDuration: const Duration(milliseconds: 50),
|
||||
builder: (BuildContext context) => const SizedBox(),
|
||||
);
|
||||
},
|
||||
child: const Text('tap'),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
));
|
||||
|
||||
// Open the dialog.
|
||||
await tester.tap(find.text('tap'));
|
||||
await tester.pump();
|
||||
|
||||
expect(rootObserver.dialogCount, 1);
|
||||
expect(nestedObserver.dialogCount, 0);
|
||||
expect(rootObserver.dialogRoutes.length, equals(1));
|
||||
final ModalRoute<dynamic> route = rootObserver.dialogRoutes.last;
|
||||
expect(route is CupertinoDialogRoute, true);
|
||||
expect(route.transitionDuration.inMilliseconds, 50);
|
||||
});
|
||||
|
||||
testWidgets('showCupertinoDialog uses nested navigator if useRootNavigator is false', (WidgetTester tester) async {
|
||||
final DialogObserver rootObserver = DialogObserver();
|
||||
final DialogObserver nestedObserver = DialogObserver();
|
||||
@ -2932,15 +2971,24 @@ class PopupObserver extends NavigatorObserver {
|
||||
}
|
||||
|
||||
class DialogObserver extends NavigatorObserver {
|
||||
int dialogCount = 0;
|
||||
final List<ModalRoute<dynamic>> dialogRoutes = <ModalRoute<dynamic>>[];
|
||||
int get dialogCount => dialogRoutes.length;
|
||||
|
||||
@override
|
||||
void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) {
|
||||
if (route is CupertinoDialogRoute) {
|
||||
dialogCount++;
|
||||
dialogRoutes.add(route);
|
||||
}
|
||||
super.didPush(route, previousRoute);
|
||||
}
|
||||
|
||||
@override
|
||||
void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) {
|
||||
if (route is CupertinoDialogRoute) {
|
||||
dialogRoutes.removeLast();
|
||||
}
|
||||
super.didPop(route, previousRoute);
|
||||
}
|
||||
}
|
||||
|
||||
class RouteSettingsObserver extends NavigatorObserver {
|
||||
|
@ -2533,6 +2533,50 @@ void main() {
|
||||
expect(currentRouteSetting.name, '/');
|
||||
});
|
||||
|
||||
testWidgets('showDialog - custom transitionDuration', (WidgetTester tester) async {
|
||||
final DialogObserver rootObserver = DialogObserver();
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
navigatorObservers: <NavigatorObserver>[rootObserver],
|
||||
home: Material(
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
return Center(
|
||||
child: ElevatedButton(
|
||||
child: const Text('X'),
|
||||
onPressed: () {
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
transitionDuration: const Duration(milliseconds: 50),
|
||||
builder: (BuildContext context) {
|
||||
return const AlertDialog(
|
||||
title: Text('Title'),
|
||||
content: Text('Y'),
|
||||
actions: <Widget>[],
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.tap(find.text('X'));
|
||||
await tester.pump();
|
||||
|
||||
expect(rootObserver.dialogRoutes.length, equals(1));
|
||||
final ModalRoute<dynamic> route = rootObserver.dialogRoutes.last;
|
||||
expect(route is DialogRoute, true);
|
||||
expect(route.barrierDismissible, isNotNull);
|
||||
expect(route.barrierColor, isNotNull);
|
||||
expect(route.transitionDuration, isNotNull);
|
||||
expect(route.transitionDuration.inMilliseconds, 50);
|
||||
});
|
||||
|
||||
testWidgets('showDialog - custom barrierLabel', (WidgetTester tester) async {
|
||||
final SemanticsTester semantics = SemanticsTester(tester);
|
||||
|
||||
@ -2829,6 +2873,50 @@ void main() {
|
||||
expect(find.text('Dialog2'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('showAdaptiveDialog - custom transitionDuration', (WidgetTester tester) async {
|
||||
final DialogObserver rootObserver = DialogObserver();
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
navigatorObservers: <NavigatorObserver>[rootObserver],
|
||||
home: Material(
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
return Center(
|
||||
child: ElevatedButton(
|
||||
child: const Text('X'),
|
||||
onPressed: () {
|
||||
showAdaptiveDialog<void>(
|
||||
context: context,
|
||||
transitionDuration: const Duration(milliseconds: 50),
|
||||
builder: (BuildContext context) {
|
||||
return const AlertDialog(
|
||||
title: Text('Title'),
|
||||
content: Text('Y'),
|
||||
actions: <Widget>[],
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.tap(find.text('X'));
|
||||
await tester.pump();
|
||||
|
||||
expect(rootObserver.dialogRoutes.length, equals(1));
|
||||
final ModalRoute<dynamic> route = rootObserver.dialogRoutes.last;
|
||||
expect(route is DialogRoute, true);
|
||||
expect(route.barrierDismissible, isNotNull);
|
||||
expect(route.barrierColor, isNotNull);
|
||||
expect(route.transitionDuration, isNotNull);
|
||||
expect(route.transitionDuration.inMilliseconds, 50);
|
||||
});
|
||||
|
||||
testWidgets('Uses open focus traversal when overridden', (WidgetTester tester) async {
|
||||
final FocusNode okNode = FocusNode();
|
||||
addTearDown(okNode.dispose);
|
||||
@ -3002,15 +3090,24 @@ class _RestorableDialogTestWidget extends StatelessWidget {
|
||||
}
|
||||
|
||||
class DialogObserver extends NavigatorObserver {
|
||||
int dialogCount = 0;
|
||||
final List<ModalRoute<dynamic>> dialogRoutes = <ModalRoute<dynamic>>[];
|
||||
int get dialogCount => dialogRoutes.length;
|
||||
|
||||
@override
|
||||
void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) {
|
||||
if (route is DialogRoute) {
|
||||
dialogCount++;
|
||||
dialogRoutes.add(route);
|
||||
}
|
||||
super.didPush(route, previousRoute);
|
||||
}
|
||||
|
||||
@override
|
||||
void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) {
|
||||
if (route is DialogRoute) {
|
||||
dialogRoutes.removeLast();
|
||||
}
|
||||
super.didPop(route, previousRoute);
|
||||
}
|
||||
}
|
||||
|
||||
class _ClosureNavigatorObserver extends NavigatorObserver {
|
||||
|
@ -5,6 +5,7 @@
|
||||
import 'dart:collection';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
@ -1920,6 +1921,233 @@ void main() {
|
||||
});
|
||||
});
|
||||
|
||||
group('DialogRoute', () {
|
||||
testWidgets('DialogRoute - default transitionDuration', (WidgetTester tester) async {
|
||||
final GlobalKey containerKey = GlobalKey();
|
||||
final DialogObserver rootObserver = DialogObserver();
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
navigatorObservers: <NavigatorObserver>[rootObserver],
|
||||
home: Builder(
|
||||
builder: (BuildContext context) {
|
||||
return ElevatedButton(
|
||||
onPressed: () {
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
builder: (BuildContext innerContext) {
|
||||
return Container(
|
||||
key: containerKey,
|
||||
color: Colors.green,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
child: const Text('Open dialog'),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// Open the dialog.
|
||||
await tester.tap(find.byType(ElevatedButton));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byKey(containerKey), findsOneWidget);
|
||||
|
||||
expect(rootObserver.dialogCount, 1);
|
||||
final ModalRoute<dynamic> route = rootObserver.dialogRoutes.last;
|
||||
expect(route is RawDialogRoute, true);
|
||||
expect(route.transitionDuration.inMilliseconds, 150);
|
||||
|
||||
// Pop the new route.
|
||||
tester.state<NavigatorState>(find.byType(Navigator)).pop();
|
||||
await tester.pump();
|
||||
expect(find.byKey(containerKey), findsOneWidget);
|
||||
|
||||
// Container should be present halfway through the transition.
|
||||
await tester.pump(const Duration(milliseconds: 75));
|
||||
expect(find.byKey(containerKey), findsOneWidget);
|
||||
|
||||
// Container should be present at the very end of the transition.
|
||||
await tester.pump(const Duration(milliseconds: 75));
|
||||
expect(find.byKey(containerKey), findsOneWidget);
|
||||
|
||||
// Container have transitioned out after 150ms.
|
||||
await tester.pump(const Duration(milliseconds: 1));
|
||||
expect(find.byKey(containerKey), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('DialogRoute - custom transitionDuration', (WidgetTester tester) async {
|
||||
final GlobalKey containerKey = GlobalKey();
|
||||
final DialogObserver rootObserver = DialogObserver();
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
navigatorObservers: <NavigatorObserver>[rootObserver],
|
||||
home: Builder(
|
||||
builder: (BuildContext context) {
|
||||
return ElevatedButton(
|
||||
onPressed: () {
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
transitionDuration: const Duration(milliseconds: 300),
|
||||
builder: (BuildContext innerContext) {
|
||||
return Container(
|
||||
key: containerKey,
|
||||
color: Colors.green,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
child: const Text('Open dialog'),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// Open the dialog.
|
||||
await tester.tap(find.byType(ElevatedButton));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byKey(containerKey), findsOneWidget);
|
||||
|
||||
expect(rootObserver.dialogCount, 1);
|
||||
final ModalRoute<dynamic> route = rootObserver.dialogRoutes.last;
|
||||
expect(route is RawDialogRoute, true);
|
||||
expect(route.transitionDuration.inMilliseconds, 300);
|
||||
|
||||
// Pop the new route.
|
||||
tester.state<NavigatorState>(find.byType(Navigator)).pop();
|
||||
await tester.pump();
|
||||
expect(find.byKey(containerKey), findsOneWidget);
|
||||
|
||||
// Container should be present halfway through the transition.
|
||||
await tester.pump(const Duration(milliseconds: 150));
|
||||
expect(find.byKey(containerKey), findsOneWidget);
|
||||
|
||||
// Container should be present at the very end of the transition.
|
||||
await tester.pump(const Duration(milliseconds: 150));
|
||||
expect(find.byKey(containerKey), findsOneWidget);
|
||||
|
||||
// Container have transitioned out after 300ms.
|
||||
await tester.pump(const Duration(milliseconds: 1));
|
||||
expect(find.byKey(containerKey), findsNothing);
|
||||
});
|
||||
});
|
||||
|
||||
group('CupertinoDialogRoute', () {
|
||||
testWidgets('CupertinoDialogRoute - default transitionDuration', (WidgetTester tester) async {
|
||||
final GlobalKey containerKey = GlobalKey();
|
||||
final DialogObserver rootObserver = DialogObserver();
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
navigatorObservers: <NavigatorObserver>[rootObserver],
|
||||
theme: ThemeData(platform: TargetPlatform.iOS),
|
||||
home: Builder(
|
||||
builder: (BuildContext context) {
|
||||
return ElevatedButton(
|
||||
onPressed: () {
|
||||
showCupertinoDialog<void>(
|
||||
context: context,
|
||||
builder: (BuildContext innerContext) {
|
||||
return Container(
|
||||
key: containerKey,
|
||||
color: Colors.green,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
child: const Text('Open dialog'),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// Open the dialog.
|
||||
await tester.tap(find.byType(ElevatedButton));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byKey(containerKey), findsOneWidget);
|
||||
|
||||
expect(rootObserver.dialogCount, 1);
|
||||
final ModalRoute<dynamic> route = rootObserver.dialogRoutes.last;
|
||||
expect(route is RawDialogRoute, true);
|
||||
expect(route.transitionDuration.inMilliseconds, 250);
|
||||
|
||||
// Pop the new route.
|
||||
tester.state<NavigatorState>(find.byType(Navigator)).pop();
|
||||
await tester.pump();
|
||||
expect(find.byKey(containerKey), findsOneWidget);
|
||||
|
||||
// Container should be present halfway through the transition.
|
||||
await tester.pump(const Duration(milliseconds: 125));
|
||||
expect(find.byKey(containerKey), findsOneWidget);
|
||||
|
||||
// Container should be present at the very end of the transition.
|
||||
await tester.pump(const Duration(milliseconds: 125));
|
||||
expect(find.byKey(containerKey), findsOneWidget);
|
||||
|
||||
// Container have transitioned out after 250ms.
|
||||
await tester.pump(const Duration(milliseconds: 1));
|
||||
expect(find.byKey(containerKey), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('CupertinoDialogRoute - custom transitionDuration', (WidgetTester tester) async {
|
||||
final GlobalKey containerKey = GlobalKey();
|
||||
final DialogObserver rootObserver = DialogObserver();
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
navigatorObservers: <NavigatorObserver>[rootObserver],
|
||||
home: Builder(
|
||||
builder: (BuildContext context) {
|
||||
return ElevatedButton(
|
||||
onPressed: () {
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
transitionDuration: const Duration(milliseconds: 100),
|
||||
builder: (BuildContext innerContext) {
|
||||
return Container(
|
||||
key: containerKey,
|
||||
color: Colors.green,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
child: const Text('Open dialog'),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// Open the dialog.
|
||||
await tester.tap(find.byType(ElevatedButton));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byKey(containerKey), findsOneWidget);
|
||||
|
||||
expect(rootObserver.dialogCount, 1);
|
||||
final ModalRoute<dynamic> route = rootObserver.dialogRoutes.last;
|
||||
expect(route is RawDialogRoute, true);
|
||||
expect(route.transitionDuration.inMilliseconds, 100);
|
||||
|
||||
// Pop the new route.
|
||||
tester.state<NavigatorState>(find.byType(Navigator)).pop();
|
||||
await tester.pump();
|
||||
expect(find.byKey(containerKey), findsOneWidget);
|
||||
|
||||
// Container should be present halfway through the transition.
|
||||
await tester.pump(const Duration(milliseconds: 50));
|
||||
expect(find.byKey(containerKey), findsOneWidget);
|
||||
|
||||
// Container should be present at the very end of the transition.
|
||||
await tester.pump(const Duration(milliseconds: 50));
|
||||
expect(find.byKey(containerKey), findsOneWidget);
|
||||
|
||||
// Container have transitioned out after 100ms.
|
||||
await tester.pump(const Duration(milliseconds: 1));
|
||||
expect(find.byKey(containerKey), findsNothing);
|
||||
});
|
||||
});
|
||||
|
||||
testWidgets('can be dismissed with escape keyboard shortcut', (WidgetTester tester) async {
|
||||
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
@ -2155,13 +2383,12 @@ class TestPageRouteBuilder extends PageRouteBuilder<void> {
|
||||
|
||||
class DialogObserver extends NavigatorObserver {
|
||||
final List<ModalRoute<dynamic>> dialogRoutes = <ModalRoute<dynamic>>[];
|
||||
int dialogCount = 0;
|
||||
int get dialogCount => dialogRoutes.length;
|
||||
|
||||
@override
|
||||
void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) {
|
||||
if (route is RawDialogRoute) {
|
||||
dialogRoutes.add(route);
|
||||
dialogCount++;
|
||||
}
|
||||
super.didPush(route, previousRoute);
|
||||
}
|
||||
@ -2170,7 +2397,6 @@ class DialogObserver extends NavigatorObserver {
|
||||
void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) {
|
||||
if (route is RawDialogRoute) {
|
||||
dialogRoutes.removeLast();
|
||||
dialogCount--;
|
||||
}
|
||||
super.didPop(route, previousRoute);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user