tween.dart 8.31 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;
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
abstract class Animatable<T> {
13 14
  /// Abstract const constructor. This constructor enables subclasses to provide
  /// const constructors so that they can be used in const expressions.
15
  const Animatable();
16

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

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

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

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

36
  @override
37
  final Animation<double> parent;
38

39
  final Animatable<T> _evaluatable;
40

41
  @override
42
  T get value => _evaluatable.evaluate(parent);
43 44 45

  @override
  String toString() {
46
    return '$parent\u27A9$_evaluatable\u27A9$value';
47 48 49 50 51 52
  }

  @override
  String toStringDetails() {
    return '${super.toStringDetails()} $_evaluatable';
  }
53 54
}

55
class _ChainedEvaluation<T> extends Animatable<T> {
56 57
  _ChainedEvaluation(this._parent, this._evaluatable);

58 59
  final Animatable<double> _parent;
  final Animatable<T> _evaluatable;
60

61
  @override
62
  T evaluate(Animation<double> animation) {
63
    double value = _parent.evaluate(animation);
64
    return _evaluatable.evaluate(new AlwaysStoppedAnimation<double>(value));
65
  }
66 67 68 69 70

  @override
  String toString() {
    return '$_parent\u27A9$_evaluatable';
  }
71 72
}

73
/// A linear interpolation between a beginning and ending value.
74 75 76
///
/// [Tween] is useful if you want to interpolate across a range.
///
77 78 79
/// To use a [Tween] object with an animation, call the [Tween] object's
/// `animate()` method and pass it the [Animation] object that you want to
/// modify.
80
///
81 82 83 84 85
/// You can chain [Tween] objects together using the `chain()` method, so that a
/// single [Animation] object is configured by multiple [Tween] objects called
/// in succession. This is different than calling the `animate()` method twice,
/// which results in two [Animation] separate objects, each configured with a
/// single [Tween].
86
class Tween<T extends dynamic> extends Animatable<T> {
87 88
  /// Creates a tween.
  ///
89 90 91
  /// The [begin] and [end] properties must be non-null before the tween is
  /// first used, but the arguments can be null if the values are going to be
  /// filled in later.
92
  Tween({ this.begin, this.end });
93 94

  /// The value this variable has at the beginning of the animation.
95 96
  ///
  /// Must be non-null before this [Tween] is evaluated.
97 98 99
  T begin;

  /// The value this variable has at the end of the animation.
100 101
  ///
  /// Must be non-null before this [Tween] is evaluated.
102 103 104
  T end;

  /// Returns the value this variable has at the given animation clock value.
105 106 107
  ///
  /// The [begin] and [end] properties must be non-null by the time this method
  /// is called.
108 109
  T lerp(double t) => begin + (end - begin) * t;

110
  /// Returns the interpolated value for the current value of the given animation.
111
  ///
112 113 114 115 116
  /// This method returns `begin` and `end` when the animation values are 0.0 or
  /// 1.0, respectively.
  ///
  /// The [begin] and [end] properties must be non-null by the time this method
  /// is called with an animation that is not at 0.0 or 1.0.
117
  @override
118
  T evaluate(Animation<double> animation) {
119
    final double t = animation.value;
120 121 122 123 124 125
    if (t == 0.0)
      return begin;
    if (t == 1.0)
      return end;
    return lerp(t);
  }
126

127
  @override
128
  String toString() => '$runtimeType($begin \u2192 $end)';
129 130
}

131
/// An interpolation between two colors.
132 133 134 135
///
/// This class specializes the interpolation of Tween<Color> to be
/// appropriate for colors.
class ColorTween extends Tween<Color> {
136 137
  /// Creates a color tween.
  ///
138 139 140
  /// The [begin] and [end] properties must be non-null before the tween is
  /// first used, but the arguments can be null if the values are going to be
  /// filled in later.
141 142
  ColorTween({ Color begin, Color end }) : super(begin: begin, end: end);

143
  @override
144 145 146
  Color lerp(double t) => Color.lerp(begin, end, t);
}

147
/// An interpolation between two sizes.
148 149 150 151
///
/// This class specializes the interpolation of Tween<Size> to be
/// appropriate for rectangles.
class SizeTween extends Tween<Size> {
152 153
  /// Creates a size tween.
  ///
154 155 156
  /// The [begin] and [end] properties must be non-null before the tween is
  /// first used, but the arguments can be null if the values are going to be
  /// filled in later.
157 158
  SizeTween({ Size begin, Size end }) : super(begin: begin, end: end);

159
  @override
160 161 162
  Size lerp(double t) => Size.lerp(begin, end, t);
}

163
/// An interpolation between two rectangles.
164 165 166 167
///
/// This class specializes the interpolation of Tween<Rect> to be
/// appropriate for rectangles.
class RectTween extends Tween<Rect> {
168 169
  /// Creates a rect tween.
  ///
170 171 172
  /// The [begin] and [end] properties must be non-null before the tween is
  /// first used, but the arguments can be null if the values are going to be
  /// filled in later.
173 174
  RectTween({ Rect begin, Rect end }) : super(begin: begin, end: end);

175
  @override
176 177 178
  Rect lerp(double t) => Rect.lerp(begin, end, t);
}

179
/// An interpolation between two integers that rounds.
180 181
///
/// This class specializes the interpolation of Tween<int> to be
182 183 184 185 186 187
/// 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].
188
class IntTween extends Tween<int> {
189 190
  /// Creates an int tween.
  ///
191 192 193
  /// The [begin] and [end] properties must be non-null before the tween is
  /// first used, but the arguments can be null if the values are going to be
  /// filled in later.
194 195 196 197
  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.
198
  @override
199 200
  int lerp(double t) => (begin + (end - begin) * t).round();
}
201

202 203 204 205 206 207 208 209 210 211
/// 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> {
212 213
  /// Creates a step tween.
  ///
214 215 216
  /// The [begin] and [end] properties must be non-null before the tween is
  /// first used, but the arguments can be null if the values are going to be
  /// filled in later.
217 218 219 220
  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.
221
  @override
222 223 224
  int lerp(double t) => (begin + (end - begin) * t).floor();
}

225 226 227 228 229
/// 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].
230
class CurveTween extends Animatable<double> {
231 232 233 234 235 236
  /// Creates a curve tween.
  ///
  /// The [curve] argument must not be null.
  CurveTween({ this.curve }) {
    assert(curve != null);
  }
237

238
  /// The curve to use when transforming the value of the animation.
239 240
  Curve curve;

241
  @override
242
  double evaluate(Animation<double> animation) {
243 244 245 246 247 248 249 250
    double t = animation.value;
    if (t == 0.0 || t == 1.0) {
      assert(curve.transform(t).round() == t);
      return t;
    }
    return curve.transform(t);
  }
}