Commit 3e3d2192 authored by Ian Hickson's avatar Ian Hickson Committed by GitHub

Curves.decelerate (#7284)

Port DecelerateInterpolator to Flutter.

Also, hide the Curve subclasses that you can't extend and that have no
statics and are generally not useful.
parent 6d4191e9
...@@ -4,12 +4,6 @@ ...@@ -4,12 +4,6 @@
import 'dart:math' as math; import 'dart:math' as math;
double _evaluateCubic(double a, double b, double m) {
return 3 * a * (1 - m) * (1 - m) * m + 3 * b * (1 - m) * m * m + m * m * m;
}
const double _kCubicErrorBound = 0.001;
/// A mapping of the unit interval to the unit interval. /// A mapping of the unit interval to the unit interval.
/// ///
/// A curve must map 0.0 to 0.0 and 1.0 to 1.0. /// A curve must map 0.0 to 0.0 and 1.0 to 1.0.
...@@ -20,9 +14,9 @@ abstract class Curve { ...@@ -20,9 +14,9 @@ abstract class Curve {
/// const constructors so that they can be used in const expressions. /// const constructors so that they can be used in const expressions.
const Curve(); const Curve();
/// Returns the value of the curve at point [t]. /// Returns the value of the curve at point `t`.
/// ///
/// The value of [t] must be between 0.0 and 1.0, inclusive. /// The value of `t` must be between 0.0 and 1.0, inclusive.
double transform(double t); double transform(double t);
/// Returns a new curve that is the reversed inversion of this one. /// Returns a new curve that is the reversed inversion of this one.
...@@ -38,8 +32,8 @@ abstract class Curve { ...@@ -38,8 +32,8 @@ abstract class Curve {
/// The identity map over the unit interval. /// The identity map over the unit interval.
/// ///
/// See [Curves.linear] for an instance of this class. /// See [Curves.linear] for an instance of this class.
class Linear extends Curve { class _Linear extends Curve {
const Linear._(); const _Linear._();
@override @override
double transform(double t) => t; double transform(double t) => t;
...@@ -105,7 +99,7 @@ class Interval extends Curve { ...@@ -105,7 +99,7 @@ class Interval extends Curve {
@override @override
String toString() { String toString() {
if (curve is! Linear) if (curve is! _Linear)
return '$runtimeType($begin\u22EF$end)\u27A9$curve'; return '$runtimeType($begin\u22EF$end)\u27A9$curve';
return '$runtimeType($begin\u22EF$end)'; return '$runtimeType($begin\u22EF$end)';
} }
...@@ -176,6 +170,14 @@ class Cubic extends Curve { ...@@ -176,6 +170,14 @@ class Cubic extends Curve {
/// to the curve at the point (1, 1). /// to the curve at the point (1, 1).
final double d; final double d;
static const double _kCubicErrorBound = 0.001;
double _evaluateCubic(double a, double b, double m) {
return 3 * a * (1 - m) * (1 - m) * m +
3 * b * (1 - m) * m * m +
m * m * m;
}
@override @override
double transform(double t) { double transform(double t) {
double start = 0.0; double start = 0.0;
...@@ -198,20 +200,6 @@ class Cubic extends Curve { ...@@ -198,20 +200,6 @@ class Cubic extends Curve {
} }
} }
double _bounce(double t) {
if (t < 1.0 / 2.75) {
return 7.5625 * t * t;
} else if (t < 2 / 2.75) {
t -= 1.5 / 2.75;
return 7.5625 * t * t + 0.75;
} else if (t < 2.5 / 2.75) {
t -= 2.25 / 2.75;
return 7.5625 * t * t + 0.9375;
}
t -= 2.625 / 2.75;
return 7.5625 * t * t + 0.984375;
}
/// A curve that is the reversed inversion of its given curve. /// A curve that is the reversed inversion of its given curve.
/// ///
/// This curve evalutes the given curve in reverse (i.e., from 1.0 to 0.0 as t /// This curve evalutes the given curve in reverse (i.e., from 1.0 to 0.0 as t
...@@ -235,11 +223,48 @@ class FlippedCurve extends Curve { ...@@ -235,11 +223,48 @@ class FlippedCurve extends Curve {
} }
} }
/// A curve where the rate of change starts out quickly and then decelerates; an
/// upside-down `f(t) = t²` parabola.
///
/// This is equivalent to the Android `DecelerateInterpolator` class with a unit
/// factor (the default factor).
///
/// See [Curves.decelerate] for an instance of this class.
class _DecelerateCurve extends Curve {
const _DecelerateCurve._();
@override
double transform(double t) {
// Intended to match the behavior of:
// https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/view/animation/DecelerateInterpolator.java
// ...as of December 2016.
t = 1.0 - t;
return 1.0 - t * t;
}
}
// BOUNCE CURVES
double _bounce(double t) {
if (t < 1.0 / 2.75) {
return 7.5625 * t * t;
} else if (t < 2 / 2.75) {
t -= 1.5 / 2.75;
return 7.5625 * t * t + 0.75;
} else if (t < 2.5 / 2.75) {
t -= 2.25 / 2.75;
return 7.5625 * t * t + 0.9375;
}
t -= 2.625 / 2.75;
return 7.5625 * t * t + 0.984375;
}
/// An oscillating curve that grows in magnitude. /// An oscillating curve that grows in magnitude.
/// ///
/// See [Curves.bounceIn] for an instance of this class. /// See [Curves.bounceIn] for an instance of this class.
class BounceInCurve extends Curve { class _BounceInCurve extends Curve {
const BounceInCurve._(); const _BounceInCurve._();
@override @override
double transform(double t) { double transform(double t) {
...@@ -250,8 +275,8 @@ class BounceInCurve extends Curve { ...@@ -250,8 +275,8 @@ class BounceInCurve extends Curve {
/// An oscillating curve that shrink in magnitude. /// An oscillating curve that shrink in magnitude.
/// ///
/// See [Curves.bounceOut] for an instance of this class. /// See [Curves.bounceOut] for an instance of this class.
class BounceOutCurve extends Curve { class _BounceOutCurve extends Curve {
const BounceOutCurve._(); const _BounceOutCurve._();
@override @override
double transform(double t) { double transform(double t) {
...@@ -262,8 +287,8 @@ class BounceOutCurve extends Curve { ...@@ -262,8 +287,8 @@ class BounceOutCurve extends Curve {
/// An oscillating curve that first grows and then shrink in magnitude. /// An oscillating curve that first grows and then shrink in magnitude.
/// ///
/// See [Curves.bounceInOut] for an instance of this class. /// See [Curves.bounceInOut] for an instance of this class.
class BounceInOutCurve extends Curve { class _BounceInOutCurve extends Curve {
const BounceInOutCurve._(); const _BounceInOutCurve._();
@override @override
double transform(double t) { double transform(double t) {
...@@ -274,6 +299,9 @@ class BounceInOutCurve extends Curve { ...@@ -274,6 +299,9 @@ class BounceInOutCurve extends Curve {
} }
} }
// ELASTIC CURVES
/// An oscillating curve that grows in magnitude while overshooting its bounds. /// An oscillating curve that grows in magnitude while overshooting its bounds.
class ElasticInCurve extends Curve { class ElasticInCurve extends Curve {
/// Creates an elastic-in curve. /// Creates an elastic-in curve.
...@@ -345,12 +373,26 @@ class ElasticInOutCurve extends Curve { ...@@ -345,12 +373,26 @@ class ElasticInOutCurve extends Curve {
} }
} }
// PREDEFINED CURVES
/// A collection of common animation curves. /// A collection of common animation curves.
class Curves { class Curves {
Curves._(); Curves._();
/// A linear animation curve /// A linear animation curve.
static const Linear linear = const Linear._(); ///
/// This is the identity map over the unit interval: its [Curve.transform]
/// method returns its input unmodified. This is useful as a default curve for
/// cases where a [Curve] is required but no actual curve is desired.
static const Curve linear = const _Linear._();
/// A curve where the rate of change starts out quickly and then decelerates; an
/// upside-down `f(t) = t²` parabola.
///
/// This is equivalent to the Android `DecelerateInterpolator` class with a unit
/// factor (the default factor).
static const Curve decelerate = const _DecelerateCurve._();
/// A cubic animation curve that speeds up quickly and ends slowly. /// A cubic animation curve that speeds up quickly and ends slowly.
static const Cubic ease = const Cubic(0.25, 0.1, 0.25, 1.0); static const Cubic ease = const Cubic(0.25, 0.1, 0.25, 1.0);
...@@ -364,14 +406,21 @@ class Curves { ...@@ -364,14 +406,21 @@ class Curves {
/// A cubic animation curve that starts slowly, speeds up, and then and ends slowly. /// A cubic animation curve that starts slowly, speeds up, and then and ends slowly.
static const Cubic easeInOut = const Cubic(0.42, 0.0, 0.58, 1.0); static const Cubic easeInOut = const Cubic(0.42, 0.0, 0.58, 1.0);
/// A curve that starts quickly and eases into its final position.
///
/// Over the course of the animation, the object spends more time near its
/// final destination. As a result, the user isn’t left waiting for the
/// animation to finish, and the negative effects of motion are minimized.
static const Cubic fastOutSlowIn = const Cubic(0.4, 0.0, 0.2, 1.0);
/// An oscillating curve that grows in magnitude. /// An oscillating curve that grows in magnitude.
static const BounceInCurve bounceIn = const BounceInCurve._(); static const Curve bounceIn = const _BounceInCurve._();
/// An oscillating curve that first grows and then shrink in magnitude. /// An oscillating curve that first grows and then shrink in magnitude.
static const BounceOutCurve bounceOut = const BounceOutCurve._(); static const Curve bounceOut = const _BounceOutCurve._();
/// An oscillating curve that first grows and then shrink in magnitude. /// An oscillating curve that first grows and then shrink in magnitude.
static const BounceInOutCurve bounceInOut = const BounceInOutCurve._(); static const Curve bounceInOut = const _BounceInOutCurve._();
/// An oscillating curve that grows in magnitude while overshootings its bounds. /// An oscillating curve that grows in magnitude while overshootings its bounds.
static const ElasticInCurve elasticIn = const ElasticInCurve(); static const ElasticInCurve elasticIn = const ElasticInCurve();
...@@ -381,11 +430,4 @@ class Curves { ...@@ -381,11 +430,4 @@ class Curves {
/// An oscillating curve that grows and then shrinks in magnitude while overshootings its bounds. /// An oscillating curve that grows and then shrinks in magnitude while overshootings its bounds.
static const ElasticInOutCurve elasticInOut = const ElasticInOutCurve(); static const ElasticInOutCurve elasticInOut = const ElasticInOutCurve();
/// A curve that starts quickly and eases into its final position.
///
/// Over the course of the animation, the object spends more time near its
/// final destination. As a result, the user isn’t left waiting for the
/// animation to finish, and the negative effects of motion are minimized.
static const Curve fastOutSlowIn = const Cubic(0.4, 0.0, 0.2, 1.0);
} }
...@@ -91,4 +91,16 @@ void main() { ...@@ -91,4 +91,16 @@ void main() {
expect(bounds[0], lessThan(0.0)); expect(bounds[0], lessThan(0.0));
expect(bounds[1], greaterThan(1.0)); expect(bounds[1], greaterThan(1.0));
}); });
test('Decelerate does so', () {
expect(Curves.decelerate, hasOneLineDescription);
List<double> bounds = estimateBounds(Curves.decelerate);
expect(bounds[0], greaterThanOrEqualTo(0.0));
expect(bounds[1], lessThanOrEqualTo(1.0));
double d1 = Curves.decelerate.transform(0.2) - Curves.decelerate.transform(0.0);
double d2 = Curves.decelerate.transform(1.0) - Curves.decelerate.transform(0.8);
expect(d2, lessThan(d1));
});
} }
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