Unverified Commit 302c0877 authored by ivirtex's avatar ivirtex Committed by GitHub

Update `CupertinoPageRoute` transition animation curves (#122275)

Update `CupertinoPageRoute` transition animation curves
parent 84078c85
...@@ -32,7 +32,7 @@ void main() { ...@@ -32,7 +32,7 @@ void main() {
// Tap some row to go to the next page. // Tap some row to go to the next page.
await tester.tap(find.text('Buy this cool color').first); await tester.tap(find.text('Buy this cool color').first);
await tester.pump(); await tester.pump();
await tester.pump(const Duration(milliseconds: 500)); await tester.pump(const Duration(milliseconds: 600));
await expectLater( await expectLater(
find.byType(CupertinoNavigationDemo), find.byType(CupertinoNavigationDemo),
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
import 'dart:math' as math; import 'dart:math' as math;
import 'dart:ui'; import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
export 'dart:ui' show Offset; export 'dart:ui' show Offset;
...@@ -1381,6 +1382,26 @@ abstract final class Curves { ...@@ -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} /// {@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); 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. /// 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} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease.mp4}
......
...@@ -136,7 +136,7 @@ mixin CupertinoRouteTransitionMixin<T> on PageRoute<T> { ...@@ -136,7 +136,7 @@ mixin CupertinoRouteTransitionMixin<T> on PageRoute<T> {
@override @override
// A relatively rigorous eyeball estimation. // A relatively rigorous eyeball estimation.
Duration get transitionDuration => const Duration(milliseconds: 400); Duration get transitionDuration => const Duration(milliseconds: 500);
@override @override
Color? get barrierColor => fullscreenDialog ? null : _kCupertinoPageTransitionBarrierColor; Color? get barrierColor => fullscreenDialog ? null : _kCupertinoPageTransitionBarrierColor;
...@@ -457,15 +457,9 @@ class CupertinoPageTransition extends StatelessWidget { ...@@ -457,15 +457,9 @@ class CupertinoPageTransition extends StatelessWidget {
(linearTransition (linearTransition
? primaryRouteAnimation ? primaryRouteAnimation
: CurvedAnimation( : 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, parent: primaryRouteAnimation,
curve: Curves.linearToEaseOut, curve: Curves.fastEaseInToSlowEaseOut,
reverseCurve: Curves.easeInToLinear, reverseCurve: Curves.fastEaseInToSlowEaseOut.flipped,
) )
).drive(_kRightMiddleTween), ).drive(_kRightMiddleTween),
_secondaryPositionAnimation = _secondaryPositionAnimation =
......
...@@ -53,7 +53,7 @@ void main() { ...@@ -53,7 +53,7 @@ void main() {
)); ));
await tester.pump(); 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 the middle of the title to be exactly in the middle of the screen.
expect(tester.getCenter(find.text('Page 2')).dx, 400.0); expect(tester.getCenter(find.text('Page 2')).dx, 400.0);
...@@ -673,7 +673,7 @@ void main() { ...@@ -673,7 +673,7 @@ void main() {
)); ));
await tester.pump(); await tester.pump();
await tester.pump(const Duration(milliseconds: 500)); await tester.pump(const Duration(milliseconds: 600));
expect(find.byType(CupertinoButton), findsOneWidget); expect(find.byType(CupertinoButton), findsOneWidget);
expect(find.text(String.fromCharCode(CupertinoIcons.back.codePoint)), findsOneWidget); expect(find.text(String.fromCharCode(CupertinoIcons.back.codePoint)), findsOneWidget);
...@@ -688,7 +688,7 @@ void main() { ...@@ -688,7 +688,7 @@ void main() {
)); ));
await tester.pump(); await tester.pump();
await tester.pump(const Duration(milliseconds: 500)); await tester.pump(const Duration(milliseconds: 600));
expect(find.widgetWithText(CupertinoButton, 'Close'), findsOneWidget); expect(find.widgetWithText(CupertinoButton, 'Close'), findsOneWidget);
...@@ -696,14 +696,14 @@ void main() { ...@@ -696,14 +696,14 @@ void main() {
await tester.tap(find.text('Close')); await tester.tap(find.text('Close'));
await tester.pump(); await tester.pump();
await tester.pump(const Duration(milliseconds: 500)); await tester.pump(const Duration(milliseconds: 600));
expect(find.text('Page 2'), findsOneWidget); expect(find.text('Page 2'), findsOneWidget);
await tester.tap(find.text(String.fromCharCode(CupertinoIcons.back.codePoint))); await tester.tap(find.text(String.fromCharCode(CupertinoIcons.back.codePoint)));
await tester.pump(); await tester.pump();
await tester.pump(const Duration(milliseconds: 500)); await tester.pump(const Duration(milliseconds: 600));
expect(find.text('Home page'), findsOneWidget); expect(find.text('Home page'), findsOneWidget);
}); });
...@@ -1157,7 +1157,7 @@ void main() { ...@@ -1157,7 +1157,7 @@ void main() {
); );
await tester.pump(); await tester.pump();
await tester.pump(const Duration(milliseconds: 500)); await tester.pump(const Duration(milliseconds: 600));
tester.state<NavigatorState>(find.byType(Navigator)).push( tester.state<NavigatorState>(find.byType(Navigator)).push(
CupertinoPageRoute<void>( CupertinoPageRoute<void>(
...@@ -1176,11 +1176,11 @@ void main() { ...@@ -1176,11 +1176,11 @@ void main() {
); );
await tester.pump(); 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.tap(find.byType(CupertinoNavigationBarBackButton));
await tester.pump(); 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. // The second page is still on top and didn't pop.
expect(find.text('A Phone'), findsOneWidget); expect(find.text('A Phone'), findsOneWidget);
...@@ -1406,13 +1406,13 @@ void main() { ...@@ -1406,13 +1406,13 @@ void main() {
); );
await tester.pump(); 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 1'), findsNothing);
expect(find.text('Page 2'), findsOneWidget); expect(find.text('Page 2'), findsOneWidget);
await tester.tap(find.text(String.fromCharCode(CupertinoIcons.back.codePoint))); await tester.tap(find.text(String.fromCharCode(CupertinoIcons.back.codePoint)));
await tester.pump(); 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 1'), findsOneWidget);
expect(find.text('Page 2'), findsNothing); expect(find.text('Page 2'), findsNothing);
}); });
......
...@@ -41,7 +41,7 @@ void main() { ...@@ -41,7 +41,7 @@ void main() {
expect(widget2TopLeft.dx, greaterThan(widget1InitialTopLeft.dx)); expect(widget2TopLeft.dx, greaterThan(widget1InitialTopLeft.dx));
// Will need to be changed if the animation curve or duration changes. // Will need to be changed if the animation curve or duration changes.
expect(widget1TransientTopLeft.dx, moreOrLessEquals(130, epsilon: 1.0)); expect(widget1TransientTopLeft.dx, moreOrLessEquals(158, epsilon: 1.0));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
...@@ -66,7 +66,7 @@ void main() { ...@@ -66,7 +66,7 @@ void main() {
expect(widget2TopLeft.dx, greaterThan(widget1InitialTopLeft.dx)); expect(widget2TopLeft.dx, greaterThan(widget1InitialTopLeft.dx));
// Will need to be changed if the animation curve or duration changes. // Will need to be changed if the animation curve or duration changes.
expect(widget1TransientTopLeft.dx, moreOrLessEquals(249, epsilon: 1.0)); expect(widget1TransientTopLeft.dx, moreOrLessEquals(220, epsilon: 1.0));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
......
...@@ -364,7 +364,7 @@ void main() { ...@@ -364,7 +364,7 @@ void main() {
// Navigate in tab 2. // Navigate in tab 2.
await tester.tap(find.text('Next')); await tester.tap(find.text('Next'));
await tester.pump(); await tester.pump();
await tester.pump(const Duration(milliseconds: 500)); await tester.pump(const Duration(milliseconds: 600));
expect(find.text('Page 2 of tab 2'), isOnstage); expect(find.text('Page 2 of tab 2'), isOnstage);
expect(find.text('Page 1 of tab 1', skipOffstage: false), isOffstage); expect(find.text('Page 1 of tab 1', skipOffstage: false), isOffstage);
...@@ -379,7 +379,7 @@ void main() { ...@@ -379,7 +379,7 @@ void main() {
// Navigate in tab 1. // Navigate in tab 1.
await tester.tap(find.text('Next')); await tester.tap(find.text('Next'));
await tester.pump(); await tester.pump();
await tester.pump(const Duration(milliseconds: 500)); await tester.pump(const Duration(milliseconds: 600));
expect(find.text('Page 2 of tab 1'), isOnstage); expect(find.text('Page 2 of tab 1'), isOnstage);
expect(find.text('Page 2 of tab 2', skipOffstage: false), isOffstage); expect(find.text('Page 2 of tab 2', skipOffstage: false), isOffstage);
...@@ -393,7 +393,7 @@ void main() { ...@@ -393,7 +393,7 @@ void main() {
// Pop in tab 2 // Pop in tab 2
await tester.tap(find.text('Back')); await tester.tap(find.text('Back'));
await tester.pump(); await tester.pump();
await tester.pump(const Duration(milliseconds: 500)); await tester.pump(const Duration(milliseconds: 600));
expect(find.text('Page 1 of tab 2'), isOnstage); expect(find.text('Page 1 of tab 2'), isOnstage);
expect(find.text('Page 2 of tab 1', skipOffstage: false), isOffstage); expect(find.text('Page 2 of tab 1', skipOffstage: false), isOffstage);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment