Skip to content

Commit

Permalink
Curves.decelerate (flutter#7284)
Browse files Browse the repository at this point in the history
Port DecelerateInterpolator to Flutter.

Also, hide the Curve subclasses that you can't extend and that have no
statics and are generally not useful.
  • Loading branch information
Hixie authored Dec 16, 2016
1 parent 6d4191e commit 3e3d219
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 43 deletions.
128 changes: 85 additions & 43 deletions packages/flutter/lib/src/animation/curves.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,6 @@

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 curve must map 0.0 to 0.0 and 1.0 to 1.0.
Expand All @@ -20,9 +14,9 @@ abstract class Curve {
/// const constructors so that they can be used in const expressions.
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);

/// Returns a new curve that is the reversed inversion of this one.
Expand All @@ -38,8 +32,8 @@ abstract class Curve {
/// The identity map over the unit interval.
///
/// See [Curves.linear] for an instance of this class.
class Linear extends Curve {
const Linear._();
class _Linear extends Curve {
const _Linear._();

@override
double transform(double t) => t;
Expand Down Expand Up @@ -105,7 +99,7 @@ class Interval extends Curve {

@override
String toString() {
if (curve is! Linear)
if (curve is! _Linear)
return '$runtimeType($begin\u22EF$end)\u27A9$curve';
return '$runtimeType($begin\u22EF$end)';
}
Expand Down Expand Up @@ -176,6 +170,14 @@ class Cubic extends Curve {
/// to the curve at the point (1, 1).
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
double transform(double t) {
double start = 0.0;
Expand All @@ -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.
///
/// This curve evalutes the given curve in reverse (i.e., from 1.0 to 0.0 as t
Expand All @@ -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.
///
/// See [Curves.bounceIn] for an instance of this class.
class BounceInCurve extends Curve {
const BounceInCurve._();
class _BounceInCurve extends Curve {
const _BounceInCurve._();

@override
double transform(double t) {
Expand All @@ -250,8 +275,8 @@ class BounceInCurve extends Curve {
/// An oscillating curve that shrink in magnitude.
///
/// See [Curves.bounceOut] for an instance of this class.
class BounceOutCurve extends Curve {
const BounceOutCurve._();
class _BounceOutCurve extends Curve {
const _BounceOutCurve._();

@override
double transform(double t) {
Expand All @@ -262,8 +287,8 @@ class BounceOutCurve extends Curve {
/// An oscillating curve that first grows and then shrink in magnitude.
///
/// See [Curves.bounceInOut] for an instance of this class.
class BounceInOutCurve extends Curve {
const BounceInOutCurve._();
class _BounceInOutCurve extends Curve {
const _BounceInOutCurve._();

@override
double transform(double t) {
Expand All @@ -274,6 +299,9 @@ class BounceInOutCurve extends Curve {
}
}


// ELASTIC CURVES

/// An oscillating curve that grows in magnitude while overshooting its bounds.
class ElasticInCurve extends Curve {
/// Creates an elastic-in curve.
Expand Down Expand Up @@ -345,12 +373,26 @@ class ElasticInOutCurve extends Curve {
}
}


// PREDEFINED CURVES

/// A collection of common animation curves.
class Curves {
Curves._();

/// A linear animation curve
static const Linear linear = const Linear._();
/// A linear animation curve.
///
/// 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.
static const Cubic ease = const Cubic(0.25, 0.1, 0.25, 1.0);
Expand All @@ -364,14 +406,21 @@ class Curves {
/// 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);

/// 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.
static const BounceInCurve bounceIn = const BounceInCurve._();
static const Curve bounceIn = const _BounceInCurve._();

/// 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.
static const BounceInOutCurve bounceInOut = const BounceInOutCurve._();
static const Curve bounceInOut = const _BounceInOutCurve._();

/// An oscillating curve that grows in magnitude while overshootings its bounds.
static const ElasticInCurve elasticIn = const ElasticInCurve();
Expand All @@ -381,11 +430,4 @@ class Curves {

/// An oscillating curve that grows and then shrinks in magnitude while overshootings its bounds.
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);
}
12 changes: 12 additions & 0 deletions packages/flutter/test/animation/curves_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,16 @@ void main() {
expect(bounds[0], lessThan(0.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));
});
}

0 comments on commit 3e3d219

Please sign in to comment.