Skip to content

Commit 302c087

Browse files
authored
Update CupertinoPageRoute transition animation curves (#122275)
Update `CupertinoPageRoute` transition animation curves
1 parent 84078c8 commit 302c087

File tree

8 files changed

+172
-156
lines changed

8 files changed

+172
-156
lines changed

dev/integration_tests/flutter_gallery/test/demo/cupertino/cupertino_navigation_demo_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ void main() {
3232
// Tap some row to go to the next page.
3333
await tester.tap(find.text('Buy this cool color').first);
3434
await tester.pump();
35-
await tester.pump(const Duration(milliseconds: 500));
35+
await tester.pump(const Duration(milliseconds: 600));
3636

3737
await expectLater(
3838
find.byType(CupertinoNavigationDemo),

packages/flutter/lib/src/animation/curves.dart

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import 'dart:math' as math;
77
import 'dart:ui';
88

9+
import 'package:flutter/cupertino.dart';
910
import 'package:flutter/foundation.dart';
1011

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

1385+
/// A curve that starts slowly, speeds up very quickly, and then ends slowly.
1386+
///
1387+
/// This curve is used by default to animate page transitions used by
1388+
/// [CupertinoPageRoute].
1389+
///
1390+
/// It has been derived from plots of native iOS 16.3
1391+
/// animation frames on iPhone 14 Pro Max.
1392+
/// Specifically, transition animation positions were measured
1393+
/// every frame and plotted against time. Then, a cubic curve was
1394+
/// strictly fit to the measured data points.
1395+
///
1396+
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_fast_ease_in_to_slow_ease_out.mp4}
1397+
static const ThreePointCubic fastEaseInToSlowEaseOut = ThreePointCubic(
1398+
Offset(0.056, 0.024),
1399+
Offset(0.108, 0.3085),
1400+
Offset(0.198, 0.541),
1401+
Offset(0.3655, 1.0),
1402+
Offset(0.5465, 0.989),
1403+
);
1404+
13841405
/// A cubic animation curve that speeds up quickly and ends slowly.
13851406
///
13861407
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease.mp4}

packages/flutter/lib/src/cupertino/route.dart

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ mixin CupertinoRouteTransitionMixin<T> on PageRoute<T> {
136136

137137
@override
138138
// A relatively rigorous eyeball estimation.
139-
Duration get transitionDuration => const Duration(milliseconds: 400);
139+
Duration get transitionDuration => const Duration(milliseconds: 500);
140140

141141
@override
142142
Color? get barrierColor => fullscreenDialog ? null : _kCupertinoPageTransitionBarrierColor;
@@ -457,15 +457,9 @@ class CupertinoPageTransition extends StatelessWidget {
457457
(linearTransition
458458
? primaryRouteAnimation
459459
: CurvedAnimation(
460-
// The curves below have been rigorously derived from plots of native
461-
// iOS animation frames. Specifically, a video was taken of a page
462-
// transition animation and the distance in each frame that the page
463-
// moved was measured. A best fit bezier curve was the fitted to the
464-
// point set, which is linearToEaseIn. Conversely, easeInToLinear is the
465-
// reflection over the origin of linearToEaseIn.
466460
parent: primaryRouteAnimation,
467-
curve: Curves.linearToEaseOut,
468-
reverseCurve: Curves.easeInToLinear,
461+
curve: Curves.fastEaseInToSlowEaseOut,
462+
reverseCurve: Curves.fastEaseInToSlowEaseOut.flipped,
469463
)
470464
).drive(_kRightMiddleTween),
471465
_secondaryPositionAnimation =

packages/flutter/test/cupertino/nav_bar_test.dart

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ void main() {
5353
));
5454

5555
await tester.pump();
56-
await tester.pump(const Duration(milliseconds: 500));
56+
await tester.pump(const Duration(milliseconds: 600));
5757

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

675675
await tester.pump();
676-
await tester.pump(const Duration(milliseconds: 500));
676+
await tester.pump(const Duration(milliseconds: 600));
677677

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

690690
await tester.pump();
691-
await tester.pump(const Duration(milliseconds: 500));
691+
await tester.pump(const Duration(milliseconds: 600));
692692

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

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

698698
await tester.pump();
699-
await tester.pump(const Duration(milliseconds: 500));
699+
await tester.pump(const Duration(milliseconds: 600));
700700

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

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

705705
await tester.pump();
706-
await tester.pump(const Duration(milliseconds: 500));
706+
await tester.pump(const Duration(milliseconds: 600));
707707

708708
expect(find.text('Home page'), findsOneWidget);
709709
});
@@ -1157,7 +1157,7 @@ void main() {
11571157
);
11581158

11591159
await tester.pump();
1160-
await tester.pump(const Duration(milliseconds: 500));
1160+
await tester.pump(const Duration(milliseconds: 600));
11611161

11621162
tester.state<NavigatorState>(find.byType(Navigator)).push(
11631163
CupertinoPageRoute<void>(
@@ -1176,11 +1176,11 @@ void main() {
11761176
);
11771177

11781178
await tester.pump();
1179-
await tester.pump(const Duration(milliseconds: 500));
1179+
await tester.pump(const Duration(milliseconds: 600));
11801180

11811181
await tester.tap(find.byType(CupertinoNavigationBarBackButton));
11821182
await tester.pump();
1183-
await tester.pump(const Duration(milliseconds: 500));
1183+
await tester.pump(const Duration(milliseconds: 600));
11841184

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

14081408
await tester.pump();
1409-
await tester.pump(const Duration(milliseconds: 500));
1409+
await tester.pump(const Duration(milliseconds: 600));
14101410
expect(find.text('Page 1'), findsNothing);
14111411
expect(find.text('Page 2'), findsOneWidget);
14121412

14131413
await tester.tap(find.text(String.fromCharCode(CupertinoIcons.back.codePoint)));
14141414
await tester.pump();
1415-
await tester.pump(const Duration(milliseconds: 500));
1415+
await tester.pump(const Duration(milliseconds: 600));
14161416
expect(find.text('Page 1'), findsOneWidget);
14171417
expect(find.text('Page 2'), findsNothing);
14181418
});

0 commit comments

Comments
 (0)