tween.dart 5.48 KB
Newer Older
1 2 3 4
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
import 'dart:ui' show Color, Size, Rect, VoidCallback;
6

7 8
import 'animation.dart';
import 'animations.dart';
9
import 'curves.dart';
10

11
/// An object that can produce a value of type T given an [Animation] as input.
12 13
abstract class Animatable<T> {
  const Animatable();
14

15
  /// The current value of this object for the given animation.
16
  T evaluate(Animation<double> animation);
17

18 19
  /// Returns a new Animation that is driven by the given animation but that
  /// takes on values determined by this object.
20
  Animation<T> animate(Animation<double> parent) {
21
    return new _AnimatedEvaluation<T>(parent, this);
22
  }
23

24 25
  /// Returns a new Animatable whose value is determined by first evaluating
  /// the given parent and then evaluating this object.
26
  Animatable<T> chain(Animatable<double> parent) {
27 28
    return new _ChainedEvaluation<T>(parent, this);
  }
29 30
}

31
class _AnimatedEvaluation<T> extends Animation<T> with AnimationWithParentMixin<double> {
32
  _AnimatedEvaluation(this.parent, this._evaluatable);
33

34
  /// The animation from which this value is derived.
35
  final Animation<double> parent;
36

37
  final Animatable<T> _evaluatable;
38

39
  T get value => _evaluatable.evaluate(parent);
40 41
}

42
class _ChainedEvaluation<T> extends Animatable<T> {
43 44
  _ChainedEvaluation(this._parent, this._evaluatable);

45 46
  final Animatable<double> _parent;
  final Animatable<T> _evaluatable;
47

48
  T evaluate(Animation<double> animation) {
49 50 51 52 53
    double value = _parent.evaluate(animation);
    return _evaluatable.evaluate(new AlwaysStoppedAnimation(value));
  }
}

54
/// A linear interpolation between a beginning and ending value.
55
class Tween<T extends dynamic> extends Animatable<T> {
56
  Tween({ this.begin, this.end });
57 58 59 60 61 62 63 64 65 66

  /// The value this variable has at the beginning of the animation.
  T begin;

  /// The value this variable has at the end of the animation.
  T end;

  /// Returns the value this variable has at the given animation clock value.
  T lerp(double t) => begin + (end - begin) * t;

67
  /// Returns the interpolated value for the current value of the given animation.
68
  T evaluate(Animation<double> animation) {
69 70
    if (end == null)
      return begin;
71
    double t = animation.value;
72 73 74 75 76 77
    if (t == 0.0)
      return begin;
    if (t == 1.0)
      return end;
    return lerp(t);
  }
78 79

  String toString() => '$runtimeType($begin \u2192 $end)';
80 81
}

82
/// An interpolation between two colors.
83 84 85 86 87 88 89 90 91
///
/// This class specializes the interpolation of Tween<Color> to be
/// appropriate for colors.
class ColorTween extends Tween<Color> {
  ColorTween({ Color begin, Color end }) : super(begin: begin, end: end);

  Color lerp(double t) => Color.lerp(begin, end, t);
}

92
/// An interpolation between two sizes.
93 94 95 96 97 98 99 100 101
///
/// This class specializes the interpolation of Tween<Size> to be
/// appropriate for rectangles.
class SizeTween extends Tween<Size> {
  SizeTween({ Size begin, Size end }) : super(begin: begin, end: end);

  Size lerp(double t) => Size.lerp(begin, end, t);
}

102
/// An interpolation between two rectangles.
103 104 105 106 107 108 109 110 111
///
/// This class specializes the interpolation of Tween<Rect> to be
/// appropriate for rectangles.
class RectTween extends Tween<Rect> {
  RectTween({ Rect begin, Rect end }) : super(begin: begin, end: end);

  Rect lerp(double t) => Rect.lerp(begin, end, t);
}

112
/// An interpolation between two integers that rounds.
113 114
///
/// This class specializes the interpolation of Tween<int> to be
115 116 117 118 119 120
/// appropriate for integers by interpolating between the given begin
/// and end values and then rounding the result to the nearest
/// integer.
///
/// This is the closest approximation to a linear tween that is
/// possible with an integer. Compare to [StepTween].
121 122 123 124 125 126 127
class IntTween extends Tween<int> {
  IntTween({ int begin, int end }) : super(begin: begin, end: end);

  // The inherited lerp() function doesn't work with ints because it multiplies
  // the begin and end types by a double, and int * double returns a double.
  int lerp(double t) => (begin + (end - begin) * t).round();
}
128

129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
/// An interpolation between two integers that floors.
///
/// This class specializes the interpolation of Tween<int> to be
/// appropriate for integers by interpolating between the given begin
/// and end values and then using [int.floor()] to return the current
/// integer component, dropping the fractional component.
///
/// This results in a value that is never greater than the equivalent
/// value from a linear double interpolation. Compare to [IntTween].
class StepTween extends Tween<int> {
  StepTween({ int begin, int end }) : super(begin: begin, end: end);

  // The inherited lerp() function doesn't work with ints because it multiplies
  // the begin and end types by a double, and int * double returns a double.
  int lerp(double t) => (begin + (end - begin) * t).floor();
}

146 147 148 149 150
/// Transforms the value of the given animation by the given curve.
///
/// This class differs from [CurvedAnimation] in that [CurvedAnimation] applies
/// a curve to an existing [Animation] object whereas [CurveTween] can be
/// chained with another [Tween] prior to receiving the underlying [Animation].
151
class CurveTween extends Animatable<double> {
152 153
  CurveTween({ this.curve });

154
  /// The curve to use when transforming the value of the animation.
155 156
  Curve curve;

157
  double evaluate(Animation<double> animation) {
158 159 160 161 162 163 164 165
    double t = animation.value;
    if (t == 0.0 || t == 1.0) {
      assert(curve.transform(t).round() == t);
      return t;
    }
    return curve.transform(t);
  }
}