Skip to content

Commit

Permalink
Update CupertinoPageRoute transition animation curves (#122275)
Browse files Browse the repository at this point in the history
Update `CupertinoPageRoute` transition animation curves
  • Loading branch information
ivirtex authored Mar 30, 2023
1 parent 84078c8 commit 302c087
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 156 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ void main() {
// Tap some row to go to the next page.
await tester.tap(find.text('Buy this cool color').first);
await tester.pump();
await tester.pump(const Duration(milliseconds: 500));
await tester.pump(const Duration(milliseconds: 600));

await expectLater(
find.byType(CupertinoNavigationDemo),
Expand Down
21 changes: 21 additions & 0 deletions packages/flutter/lib/src/animation/curves.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import 'dart:math' as math;
import 'dart:ui';

import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';

export 'dart:ui' show Offset;
Expand Down Expand Up @@ -1381,6 +1382,26 @@ abstract final class Curves {
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_fast_linear_to_slow_ease_in.mp4}
static const Cubic fastLinearToSlowEaseIn = Cubic(0.18, 1.0, 0.04, 1.0);

/// A curve that starts slowly, speeds up very quickly, and then ends slowly.
///
/// This curve is used by default to animate page transitions used by
/// [CupertinoPageRoute].
///
/// It has been derived from plots of native iOS 16.3
/// animation frames on iPhone 14 Pro Max.
/// Specifically, transition animation positions were measured
/// every frame and plotted against time. Then, a cubic curve was
/// strictly fit to the measured data points.
///
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_fast_ease_in_to_slow_ease_out.mp4}
static const ThreePointCubic fastEaseInToSlowEaseOut = ThreePointCubic(
Offset(0.056, 0.024),
Offset(0.108, 0.3085),
Offset(0.198, 0.541),
Offset(0.3655, 1.0),
Offset(0.5465, 0.989),
);

/// A cubic animation curve that speeds up quickly and ends slowly.
///
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease.mp4}
Expand Down
12 changes: 3 additions & 9 deletions packages/flutter/lib/src/cupertino/route.dart
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ mixin CupertinoRouteTransitionMixin<T> on PageRoute<T> {

@override
// A relatively rigorous eyeball estimation.
Duration get transitionDuration => const Duration(milliseconds: 400);
Duration get transitionDuration => const Duration(milliseconds: 500);

@override
Color? get barrierColor => fullscreenDialog ? null : _kCupertinoPageTransitionBarrierColor;
Expand Down Expand Up @@ -457,15 +457,9 @@ class CupertinoPageTransition extends StatelessWidget {
(linearTransition
? primaryRouteAnimation
: CurvedAnimation(
// The curves below have been rigorously derived from plots of native
// iOS animation frames. Specifically, a video was taken of a page
// transition animation and the distance in each frame that the page
// moved was measured. A best fit bezier curve was the fitted to the
// point set, which is linearToEaseIn. Conversely, easeInToLinear is the
// reflection over the origin of linearToEaseIn.
parent: primaryRouteAnimation,
curve: Curves.linearToEaseOut,
reverseCurve: Curves.easeInToLinear,
curve: Curves.fastEaseInToSlowEaseOut,
reverseCurve: Curves.fastEaseInToSlowEaseOut.flipped,
)
).drive(_kRightMiddleTween),
_secondaryPositionAnimation =
Expand Down
20 changes: 10 additions & 10 deletions packages/flutter/test/cupertino/nav_bar_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ void main() {
));

await tester.pump();
await tester.pump(const Duration(milliseconds: 500));
await tester.pump(const Duration(milliseconds: 600));

// Expect the middle of the title to be exactly in the middle of the screen.
expect(tester.getCenter(find.text('Page 2')).dx, 400.0);
Expand Down Expand Up @@ -673,7 +673,7 @@ void main() {
));

await tester.pump();
await tester.pump(const Duration(milliseconds: 500));
await tester.pump(const Duration(milliseconds: 600));

expect(find.byType(CupertinoButton), findsOneWidget);
expect(find.text(String.fromCharCode(CupertinoIcons.back.codePoint)), findsOneWidget);
Expand All @@ -688,22 +688,22 @@ void main() {
));

await tester.pump();
await tester.pump(const Duration(milliseconds: 500));
await tester.pump(const Duration(milliseconds: 600));

expect(find.widgetWithText(CupertinoButton, 'Close'), findsOneWidget);

// Test popping goes back correctly.
await tester.tap(find.text('Close'));

await tester.pump();
await tester.pump(const Duration(milliseconds: 500));
await tester.pump(const Duration(milliseconds: 600));

expect(find.text('Page 2'), findsOneWidget);

await tester.tap(find.text(String.fromCharCode(CupertinoIcons.back.codePoint)));

await tester.pump();
await tester.pump(const Duration(milliseconds: 500));
await tester.pump(const Duration(milliseconds: 600));

expect(find.text('Home page'), findsOneWidget);
});
Expand Down Expand Up @@ -1157,7 +1157,7 @@ void main() {
);

await tester.pump();
await tester.pump(const Duration(milliseconds: 500));
await tester.pump(const Duration(milliseconds: 600));

tester.state<NavigatorState>(find.byType(Navigator)).push(
CupertinoPageRoute<void>(
Expand All @@ -1176,11 +1176,11 @@ void main() {
);

await tester.pump();
await tester.pump(const Duration(milliseconds: 500));
await tester.pump(const Duration(milliseconds: 600));

await tester.tap(find.byType(CupertinoNavigationBarBackButton));
await tester.pump();
await tester.pump(const Duration(milliseconds: 500));
await tester.pump(const Duration(milliseconds: 600));

// The second page is still on top and didn't pop.
expect(find.text('A Phone'), findsOneWidget);
Expand Down Expand Up @@ -1406,13 +1406,13 @@ void main() {
);

await tester.pump();
await tester.pump(const Duration(milliseconds: 500));
await tester.pump(const Duration(milliseconds: 600));
expect(find.text('Page 1'), findsNothing);
expect(find.text('Page 2'), findsOneWidget);

await tester.tap(find.text(String.fromCharCode(CupertinoIcons.back.codePoint)));
await tester.pump();
await tester.pump(const Duration(milliseconds: 500));
await tester.pump(const Duration(milliseconds: 600));
expect(find.text('Page 1'), findsOneWidget);
expect(find.text('Page 2'), findsNothing);
});
Expand Down
Loading

0 comments on commit 302c087

Please sign in to comment.