Adjust remaining Cupertino route animations to match native (#28597)
This commit is contained in:
committed by
xster
parent
e525e64270
commit
4418ec467b
@@ -417,9 +417,13 @@ class CupertinoFullscreenDialogTransition extends StatelessWidget {
|
||||
Key key,
|
||||
@required Animation<double> animation,
|
||||
@required this.child,
|
||||
}) : _positionAnimation = animation
|
||||
.drive(CurveTween(curve: Curves.easeInOut))
|
||||
.drive(_kBottomUpTween),
|
||||
}) : _positionAnimation = CurvedAnimation(
|
||||
parent: animation,
|
||||
curve: Curves.linearToEaseOut,
|
||||
// The curve must be flipped so that the reverse animation doesn't play
|
||||
// an ease-in curve, which iOS does not use.
|
||||
reverseCurve: Curves.linearToEaseOut.flipped,
|
||||
).drive(_kBottomUpTween),
|
||||
super(key: key);
|
||||
|
||||
final Animation<Offset> _positionAnimation;
|
||||
@@ -816,8 +820,11 @@ class _CupertinoModalPopupRoute<T> extends PopupRoute<T> {
|
||||
assert(_animation == null);
|
||||
_animation = CurvedAnimation(
|
||||
parent: super.createAnimation(),
|
||||
curve: Curves.ease,
|
||||
reverseCurve: Curves.ease.flipped,
|
||||
|
||||
// These curves were initially measured from native iOS horizontal page
|
||||
// route animations and seemed to be a good match here as well.
|
||||
curve: Curves.linearToEaseOut,
|
||||
reverseCurve: Curves.linearToEaseOut.flipped,
|
||||
);
|
||||
_offsetTween = Tween<Offset>(
|
||||
begin: const Offset(0.0, 1.0),
|
||||
@@ -879,8 +886,11 @@ Future<T> showCupertinoModalPopup<T>({
|
||||
);
|
||||
}
|
||||
|
||||
final Animatable<double> _dialogTween = Tween<double>(begin: 1.2, end: 1.0)
|
||||
.chain(CurveTween(curve: Curves.fastOutSlowIn));
|
||||
// The curve and initial scale values were mostly eyeballed from iOS, however
|
||||
// they reuse the same animation curve that was modelled after native page
|
||||
// transitions.
|
||||
final Animatable<double> _dialogScaleTween = Tween<double>(begin: 1.3, end: 1.0)
|
||||
.chain(CurveTween(curve: Curves.linearToEaseOut));
|
||||
|
||||
Widget _buildCupertinoDialogTransitions(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
|
||||
final CurvedAnimation fadeAnimation = CurvedAnimation(
|
||||
@@ -897,7 +907,7 @@ Widget _buildCupertinoDialogTransitions(BuildContext context, Animation<double>
|
||||
opacity: fadeAnimation,
|
||||
child: ScaleTransition(
|
||||
child: child,
|
||||
scale: animation.drive(_dialogTween),
|
||||
scale: animation.drive(_dialogScaleTween),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -941,7 +951,8 @@ Future<T> showCupertinoDialog<T>({
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
barrierColor: _kModalBarrierColor,
|
||||
transitionDuration: const Duration(milliseconds: 300),
|
||||
// This transition duration was eyeballed comparing with iOS
|
||||
transitionDuration: const Duration(milliseconds: 250),
|
||||
pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
|
||||
return builder(context);
|
||||
},
|
||||
|
||||
@@ -718,19 +718,19 @@ void main() {
|
||||
expect(tester.getTopLeft(find.byType(CupertinoActionSheet)).dy, 600.0);
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 60));
|
||||
expect(tester.getTopLeft(find.byType(CupertinoActionSheet)).dy, closeTo(530.9, 0.1));
|
||||
expect(tester.getTopLeft(find.byType(CupertinoActionSheet)).dy, closeTo(470.0, 0.1));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 60));
|
||||
expect(tester.getTopLeft(find.byType(CupertinoActionSheet)).dy, closeTo(426.7, 0.1));
|
||||
expect(tester.getTopLeft(find.byType(CupertinoActionSheet)).dy, closeTo(374.3, 0.1));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 60));
|
||||
expect(tester.getTopLeft(find.byType(CupertinoActionSheet)).dy, closeTo(365.0, 0.1));
|
||||
expect(tester.getTopLeft(find.byType(CupertinoActionSheet)).dy, closeTo(337.1, 0.1));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 60));
|
||||
expect(tester.getTopLeft(find.byType(CupertinoActionSheet)).dy, closeTo(334.0, 0.1));
|
||||
expect(tester.getTopLeft(find.byType(CupertinoActionSheet)).dy, closeTo(325.3, 0.1));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 60));
|
||||
expect(tester.getTopLeft(find.byType(CupertinoActionSheet)).dy, closeTo(321.0, 0.1));
|
||||
expect(tester.getTopLeft(find.byType(CupertinoActionSheet)).dy, closeTo(320.8, 0.1));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 60));
|
||||
expect(tester.getTopLeft(find.byType(CupertinoActionSheet)).dy, closeTo(319.3, 0.1));
|
||||
@@ -745,19 +745,19 @@ void main() {
|
||||
expect(tester.getTopLeft(find.byType(CupertinoActionSheet)).dy, closeTo(319.3, 0.1));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 60));
|
||||
expect(tester.getTopLeft(find.byType(CupertinoActionSheet)).dy, closeTo(388.4, 0.1));
|
||||
expect(tester.getTopLeft(find.byType(CupertinoActionSheet)).dy, closeTo(449.3, 0.1));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 60));
|
||||
expect(tester.getTopLeft(find.byType(CupertinoActionSheet)).dy, closeTo(492.6, 0.1));
|
||||
expect(tester.getTopLeft(find.byType(CupertinoActionSheet)).dy, closeTo(544.9, 0.1));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 60));
|
||||
expect(tester.getTopLeft(find.byType(CupertinoActionSheet)).dy, closeTo(554.2, 0.1));
|
||||
expect(tester.getTopLeft(find.byType(CupertinoActionSheet)).dy, closeTo(582.1, 0.1));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 60));
|
||||
expect(tester.getTopLeft(find.byType(CupertinoActionSheet)).dy, closeTo(585.2, 0.1));
|
||||
expect(tester.getTopLeft(find.byType(CupertinoActionSheet)).dy, closeTo(593.9, 0.1));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 60));
|
||||
expect(tester.getTopLeft(find.byType(CupertinoActionSheet)).dy, closeTo(598.2, 0.1));
|
||||
expect(tester.getTopLeft(find.byType(CupertinoActionSheet)).dy, closeTo(598.5, 0.1));
|
||||
|
||||
// Action sheet has disappeared
|
||||
await tester.pump(const Duration(milliseconds: 60));
|
||||
@@ -795,23 +795,23 @@ void main() {
|
||||
expect(tester.getTopLeft(find.byType(CupertinoActionSheet)).dy, 600.0);
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 60));
|
||||
expect(tester.getTopLeft(find.byType(CupertinoActionSheet)).dy, closeTo(530.9, 0.1));
|
||||
expect(tester.getTopLeft(find.byType(CupertinoActionSheet)).dy, closeTo(470.0, 0.1));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 60));
|
||||
expect(tester.getTopLeft(find.byType(CupertinoActionSheet)).dy, closeTo(426.7, 0.1));
|
||||
expect(tester.getTopLeft(find.byType(CupertinoActionSheet)).dy, closeTo(374.3, 0.1));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 60));
|
||||
expect(tester.getTopLeft(find.byType(CupertinoActionSheet)).dy, closeTo(365.0, 0.1));
|
||||
expect(tester.getTopLeft(find.byType(CupertinoActionSheet)).dy, closeTo(337.1, 0.1));
|
||||
|
||||
// Exit animation
|
||||
await tester.tapAt(const Offset(20.0, 20.0));
|
||||
await tester.pump(const Duration(milliseconds: 60));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 60));
|
||||
expect(tester.getTopLeft(find.byType(CupertinoActionSheet)).dy, closeTo(426.7, 0.1));
|
||||
expect(tester.getTopLeft(find.byType(CupertinoActionSheet)).dy, closeTo(374.3, 0.1));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 60));
|
||||
expect(tester.getTopLeft(find.byType(CupertinoActionSheet)).dy, closeTo(530.9, 0.1));
|
||||
expect(tester.getTopLeft(find.byType(CupertinoActionSheet)).dy, closeTo(470.0, 0.1));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 60));
|
||||
expect(tester.getTopLeft(find.byType(CupertinoActionSheet)).dy, 600.0);
|
||||
|
||||
@@ -847,15 +847,11 @@ void main() {
|
||||
// Enter animation.
|
||||
await tester.pump();
|
||||
Transform transform = tester.widget(find.byType(Transform));
|
||||
expect(transform.transform[0], closeTo(1.2, 0.01));
|
||||
expect(transform.transform[0], closeTo(1.3, 0.01));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 50));
|
||||
transform = tester.widget(find.byType(Transform));
|
||||
expect(transform.transform[0], closeTo(1.182, 0.001));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 50));
|
||||
transform = tester.widget(find.byType(Transform));
|
||||
expect(transform.transform[0], closeTo(1.108, 0.001));
|
||||
expect(transform.transform[0], closeTo(1.145, 0.001));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 50));
|
||||
transform = tester.widget(find.byType(Transform));
|
||||
@@ -863,7 +859,7 @@ void main() {
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 50));
|
||||
transform = tester.widget(find.byType(Transform));
|
||||
expect(transform.transform[0], closeTo(1.015, 0.001));
|
||||
expect(transform.transform[0], closeTo(1.013, 0.001));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 50));
|
||||
transform = tester.widget(find.byType(Transform));
|
||||
@@ -873,6 +869,10 @@ void main() {
|
||||
transform = tester.widget(find.byType(Transform));
|
||||
expect(transform.transform[0], closeTo(1.000, 0.001));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 50));
|
||||
transform = tester.widget(find.byType(Transform));
|
||||
expect(transform.transform[0], closeTo(1.000, 0.001));
|
||||
|
||||
await tester.tap(find.text('Delete'));
|
||||
|
||||
await tester.pump();
|
||||
@@ -951,23 +951,23 @@ void main() {
|
||||
// Exit animation, look at reverse FadeTransition.
|
||||
await tester.pump(const Duration(milliseconds: 25));
|
||||
transition = tester.widgetList(find.byType(FadeTransition)).elementAt(1);
|
||||
expect(transition.opacity.value, closeTo(0.358, 0.001));
|
||||
expect(transition.opacity.value, closeTo(0.500, 0.001));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 25));
|
||||
transition = tester.widgetList(find.byType(FadeTransition)).elementAt(1);
|
||||
expect(transition.opacity.value, closeTo(0.231, 0.001));
|
||||
expect(transition.opacity.value, closeTo(0.332, 0.001));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 25));
|
||||
transition = tester.widgetList(find.byType(FadeTransition)).elementAt(1);
|
||||
expect(transition.opacity.value, closeTo(0.128, 0.001));
|
||||
expect(transition.opacity.value, closeTo(0.188, 0.001));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 25));
|
||||
transition = tester.widgetList(find.byType(FadeTransition)).elementAt(1);
|
||||
expect(transition.opacity.value, closeTo(0.056, 0.001));
|
||||
expect(transition.opacity.value, closeTo(0.081, 0.001));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 25));
|
||||
transition = tester.widgetList(find.byType(FadeTransition)).elementAt(1);
|
||||
expect(transition.opacity.value, closeTo(0.013, 0.001));
|
||||
expect(transition.opacity.value, closeTo(0.019, 0.001));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 25));
|
||||
transition = tester.widgetList(find.byType(FadeTransition)).elementAt(1);
|
||||
|
||||
@@ -328,4 +328,107 @@ void main() {
|
||||
expect(find.text('route'), findsOneWidget);
|
||||
expect(find.text('push'), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('Fullscreen route animates correct transform values over time', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
CupertinoApp(
|
||||
home: Builder(
|
||||
builder: (BuildContext context) {
|
||||
return CupertinoButton(
|
||||
child: const Text('Button'),
|
||||
onPressed: () {
|
||||
Navigator.push<void>(context, CupertinoPageRoute<void>(
|
||||
fullscreenDialog: true,
|
||||
builder: (BuildContext context) {
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
const Placeholder(),
|
||||
CupertinoButton(
|
||||
child: const Text('Close'),
|
||||
onPressed: () {
|
||||
Navigator.pop<void>(context);
|
||||
},
|
||||
)
|
||||
],
|
||||
);
|
||||
},
|
||||
));
|
||||
},
|
||||
);
|
||||
}
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// Enter animation.
|
||||
await tester.tap(find.text('Button'));
|
||||
await tester.pump();
|
||||
|
||||
// We use a higher number of intervals since the animation has to scale the
|
||||
// entire screen.
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 40));
|
||||
expect(tester.getTopLeft(find.byType(Placeholder)).dy, closeTo(443.7, 0.1));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 40));
|
||||
expect(tester.getTopLeft(find.byType(Placeholder)).dy, closeTo(291.9, 0.1));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 40));
|
||||
expect(tester.getTopLeft(find.byType(Placeholder)).dy, closeTo(168.2, 0.1));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 40));
|
||||
expect(tester.getTopLeft(find.byType(Placeholder)).dy, closeTo(89.5, 0.1));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 40));
|
||||
expect(tester.getTopLeft(find.byType(Placeholder)).dy, closeTo(48.1, 0.1));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 40));
|
||||
expect(tester.getTopLeft(find.byType(Placeholder)).dy, closeTo(26.1, 0.1));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 40));
|
||||
expect(tester.getTopLeft(find.byType(Placeholder)).dy, closeTo(14.3, 0.1));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 40));
|
||||
expect(tester.getTopLeft(find.byType(Placeholder)).dy, closeTo(7.41, 0.1));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 40));
|
||||
expect(tester.getTopLeft(find.byType(Placeholder)).dy, closeTo(3.0, 0.1));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 40));
|
||||
expect(tester.getTopLeft(find.byType(Placeholder)).dy, closeTo(0.0, 0.1));
|
||||
|
||||
// Exit animation
|
||||
await tester.tap(find.text('Close'));
|
||||
await tester.pump();
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 40));
|
||||
expect(tester.getTopLeft(find.byType(Placeholder)).dy, closeTo(156.3, 0.1));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 40));
|
||||
expect(tester.getTopLeft(find.byType(Placeholder)).dy, closeTo(308.1, 0.1));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 40));
|
||||
expect(tester.getTopLeft(find.byType(Placeholder)).dy, closeTo(431.7, 0.1));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 40));
|
||||
expect(tester.getTopLeft(find.byType(Placeholder)).dy, closeTo(510.4, 0.1));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 40));
|
||||
expect(tester.getTopLeft(find.byType(Placeholder)).dy, closeTo(551.8, 0.1));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 40));
|
||||
expect(tester.getTopLeft(find.byType(Placeholder)).dy, closeTo(573.8, 0.1));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 40));
|
||||
expect(tester.getTopLeft(find.byType(Placeholder)).dy, closeTo(585.6, 0.1));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 40));
|
||||
expect(tester.getTopLeft(find.byType(Placeholder)).dy, closeTo(592.6, 0.1));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 40));
|
||||
expect(tester.getTopLeft(find.byType(Placeholder)).dy, closeTo(596.9, 0.1));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 40));
|
||||
expect(tester.getTopLeft(find.byType(Placeholder)).dy, closeTo(600.0, 0.1));
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user