From 6007f6af364a22b661404eb729d2e74fa19107ce Mon Sep 17 00:00:00 2001 From: Matt Perry Date: Wed, 31 Aug 2016 13:50:38 -0400 Subject: [PATCH] Use fastOutSlowIn curve for transitions on iOS when not controlled by user gesture. (#5666) BUG=https://github.com/flutter/flutter/issues/5599 --- packages/flutter/lib/src/material/page.dart | 39 ++++++++++++++++----- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/packages/flutter/lib/src/material/page.dart b/packages/flutter/lib/src/material/page.dart index 2b6372be17..c69db7c57c 100644 --- a/packages/flutter/lib/src/material/page.dart +++ b/packages/flutter/lib/src/material/page.dart @@ -48,13 +48,14 @@ class _CupertinoPageTransition extends AnimatedWidget { _CupertinoPageTransition({ Key key, + Curve curve, Animation animation, this.child }) : super( key: key, animation: _kTween.animate(new CurvedAnimation( parent: animation, - curve: new _CupertinoTransitionCurve() + curve: new _CupertinoTransitionCurve(curve) ) )); @@ -84,16 +85,33 @@ class AnimationMean extends CompoundAnimation { double get value => (first.value + next.value) / 2.0; } -// Custom curve for iOS page transitions. The halfway point is when the page -// is fully on-screen. 0.0 is fully off-screen to the right. 1.0 is off-screen -// to the left. +// Custom curve for iOS page transitions. class _CupertinoTransitionCurve extends Curve { - _CupertinoTransitionCurve(); + _CupertinoTransitionCurve(this.curve); + + Curve curve; @override double transform(double t) { - if (t > 0.5) - return (t - 0.5) / 3.0 + 0.5; + // The input [t] is the average of the current and next route's animation. + // This means t=0.5 represents when the route is fully onscreen. At + // t > 0.5, it is partially offscreen to the left (which happens when there + // is another route on top). At t < 0.5, the route is to the right. + // We divide the range into two halves, each with a different transition, + // and scale each half to the range [0.0, 1.0] before applying curves so that + // each half goes through the full range of the curve. + if (t > 0.5) { + // Route is to the left of center. + t = (t - 0.5) * 2.0; + if (curve != null) + t = curve.transform(t); + t = t / 3.0; + t = t / 2.0 + 0.5; + } else { + // Route is to the right of center. + if (curve != null) + t = curve.transform(t * 2.0) / 2.0; + } return t; } } @@ -220,7 +238,8 @@ class MaterialPageRoute extends PageRoute { // TODO(mpcomplete): This hack prevents the previousRoute from animating // when we pop(). Remove once we fix this bug: // https://github.com/flutter/flutter/issues/5577 - if (!Navigator.of(context).userGestureInProgress) + bool userGesture = Navigator.of(context).userGestureInProgress; + if (!userGesture) forwardAnimation = kAlwaysDismissedAnimation; ThemeData theme = Theme.of(context); @@ -233,6 +252,10 @@ class MaterialPageRoute extends PageRoute { ); case TargetPlatform.iOS: return new _CupertinoPageTransition( + // Use a linear curve when controlled by a user gesture. This ensures + // the animation tracks the user's finger 1:1. + // See https://github.com/flutter/flutter/issues/5664 + curve: userGesture ? null : Curves.fastOutSlowIn, animation: new AnimationMean(left: animation, right: forwardAnimation), child: child );