1 | // Copyright 2014 The Flutter Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | import 'dart:ui' show Color, Rect, Size; |
6 | |
7 | import 'package:flutter/foundation.dart'; |
8 | |
9 | import 'animations.dart'; |
10 | |
11 | export 'dart:ui' show Color, Rect, Size; |
12 | |
13 | export 'animation.dart' show Animation; |
14 | export 'curves.dart' show Curve; |
15 | |
16 | // Examples can assume: |
17 | // late Animation _animation; |
18 | // late AnimationController _controller; |
19 | |
20 | /// A typedef used by [Animatable.fromCallback] to create an [Animatable] |
21 | /// from a callback. |
22 | typedef AnimatableCallback<T> = T Function(double value); |
23 | |
24 | /// An object that can produce a value of type `T` given an [Animation<double>] |
25 | /// as input. |
26 | /// |
27 | /// Typically, the values of the input animation are nominally in the range 0.0 |
28 | /// to 1.0. In principle, however, any value could be provided. |
29 | /// |
30 | /// The main subclass of [Animatable] is [Tween]. |
31 | abstract class Animatable<T> { |
32 | /// Abstract const constructor. This constructor enables subclasses to provide |
33 | /// const constructors so that they can be used in const expressions. |
34 | const Animatable(); |
35 | |
36 | /// Create a new [Animatable] from the provided [callback]. |
37 | /// |
38 | /// See also: |
39 | /// |
40 | /// * [Animation.drive], which provides an example for how this can be |
41 | /// used. |
42 | const factory Animatable.fromCallback(AnimatableCallback<T> callback) = _CallbackAnimatable<T>; |
43 | |
44 | /// Returns the value of the object at point `t`. |
45 | /// |
46 | /// The value of `t` is nominally a fraction in the range 0.0 to 1.0, though |
47 | /// in practice it may extend outside this range. |
48 | /// |
49 | /// See also: |
50 | /// |
51 | /// * [evaluate], which is a shorthand for applying [transform] to the value |
52 | /// of an [Animation]. |
53 | /// * [Curve.transform], a similar method for easing curves. |
54 | T transform(double t); |
55 | |
56 | /// The current value of this object for the given [Animation]. |
57 | /// |
58 | /// This function is implemented by deferring to [transform]. Subclasses that |
59 | /// want to provide custom behavior should override [transform], not |
60 | /// [evaluate]. |
61 | /// |
62 | /// See also: |
63 | /// |
64 | /// * [transform], which is similar but takes a `t` value directly instead of |
65 | /// an [Animation]. |
66 | /// * [animate], which creates an [Animation] out of this object, continually |
67 | /// applying [evaluate]. |
68 | T evaluate(Animation<double> animation) => transform(animation.value); |
69 | |
70 | /// Returns a new [Animation] that is driven by the given animation but that |
71 | /// takes on values determined by this object. |
72 | /// |
73 | /// Essentially this returns an [Animation] that automatically applies the |
74 | /// [evaluate] method to the parent's value. |
75 | /// |
76 | /// See also: |
77 | /// |
78 | /// * [AnimationController.drive], which does the same thing from the |
79 | /// opposite starting point. |
80 | Animation<T> animate(Animation<double> parent) { |
81 | return _AnimatedEvaluation<T>(parent, this); |
82 | } |
83 | |
84 | /// Returns a new [Animatable] whose value is determined by first evaluating |
85 | /// the given parent and then evaluating this object. |
86 | /// |
87 | /// This allows [Tween]s to be chained before obtaining an [Animation]. |
88 | Animatable<T> chain(Animatable<double> parent) { |
89 | return _ChainedEvaluation<T>(parent, this); |
90 | } |
91 | } |
92 | |
93 | // A concrete subclass of `Animatable` used by `Animatable.fromCallback`. |
94 | class _CallbackAnimatable<T> extends Animatable<T> { |
95 | const _CallbackAnimatable(this._callback); |
96 | |
97 | final AnimatableCallback<T> _callback; |
98 | |
99 | @override |
100 | T transform(double t) { |
101 | return _callback(t); |
102 | } |
103 | } |
104 | |
105 | class _AnimatedEvaluation<T> extends Animation<T> with AnimationWithParentMixin<double> { |
106 | _AnimatedEvaluation(this.parent, this._evaluatable); |
107 | |
108 | @override |
109 | final Animation<double> parent; |
110 | |
111 | final Animatable<T> _evaluatable; |
112 | |
113 | @override |
114 | T get value => _evaluatable.evaluate(parent); |
115 | |
116 | @override |
117 | String toString() { |
118 | return ' $parent\u27A9 $_evaluatable\u27A9 $value' ; |
119 | } |
120 | |
121 | @override |
122 | String toStringDetails() { |
123 | return ' ${super.toStringDetails()} $_evaluatable' ; |
124 | } |
125 | } |
126 | |
127 | class _ChainedEvaluation<T> extends Animatable<T> { |
128 | _ChainedEvaluation(this._parent, this._evaluatable); |
129 | |
130 | final Animatable<double> _parent; |
131 | final Animatable<T> _evaluatable; |
132 | |
133 | @override |
134 | T transform(double t) { |
135 | return _evaluatable.transform(_parent.transform(t)); |
136 | } |
137 | |
138 | @override |
139 | String toString() { |
140 | return ' $_parent\u27A9 $_evaluatable' ; |
141 | } |
142 | } |
143 | |
144 | /// A linear interpolation between a beginning and ending value. |
145 | /// |
146 | /// [Tween] is useful if you want to interpolate across a range. |
147 | /// |
148 | /// To use a [Tween] object with an animation, call the [Tween] object's |
149 | /// [animate] method and pass it the [Animation] object that you want to |
150 | /// modify. |
151 | /// |
152 | /// You can chain [Tween] objects together using the [chain] method, so that a |
153 | /// single [Animation] object is configured by multiple [Tween] objects called |
154 | /// in succession. This is different than calling the [animate] method twice, |
155 | /// which results in two separate [Animation] objects, each configured with a |
156 | /// single [Tween]. |
157 | /// |
158 | /// {@tool snippet} |
159 | /// |
160 | /// Suppose `_controller` is an [AnimationController], and we want to create an |
161 | /// [Animation<Offset>] that is controlled by that controller, and save it in |
162 | /// `_animation`. Here are two possible ways of expressing this: |
163 | /// |
164 | /// ```dart |
165 | /// _animation = _controller.drive( |
166 | /// Tween<Offset>( |
167 | /// begin: const Offset(100.0, 50.0), |
168 | /// end: const Offset(200.0, 300.0), |
169 | /// ), |
170 | /// ); |
171 | /// ``` |
172 | /// {@end-tool} |
173 | /// {@tool snippet} |
174 | /// |
175 | /// ```dart |
176 | /// _animation = Tween<Offset>( |
177 | /// begin: const Offset(100.0, 50.0), |
178 | /// end: const Offset(200.0, 300.0), |
179 | /// ).animate(_controller); |
180 | /// ``` |
181 | /// {@end-tool} |
182 | /// |
183 | /// In both cases, the `_animation` variable holds an object that, over the |
184 | /// lifetime of the `_controller`'s animation, returns a value |
185 | /// (`_animation.value`) that depicts a point along the line between the two |
186 | /// offsets above. If we used a [MaterialPointArcTween] instead of a |
187 | /// [Tween<Offset>] in the code above, the points would follow a pleasing curve |
188 | /// instead of a straight line, with no other changes necessary. |
189 | /// |
190 | /// ## Performance optimizations |
191 | /// |
192 | /// Tweens are mutable; specifically, their [begin] and [end] values can be |
193 | /// changed at runtime. An object created with [Animation.drive] using a [Tween] |
194 | /// will immediately honor changes to that underlying [Tween] (though the |
195 | /// listeners will only be triggered if the [Animation] is actively animating). |
196 | /// This can be used to change an animation on the fly without having to |
197 | /// recreate all the objects in the chain from the [AnimationController] to the |
198 | /// final [Tween]. |
199 | /// |
200 | /// If a [Tween]'s values are never changed, however, a further optimization can |
201 | /// be applied: the object can be stored in a `static final` variable, so that |
202 | /// the exact same instance is used whenever the [Tween] is needed. This is |
203 | /// preferable to creating an identical [Tween] afresh each time a [State.build] |
204 | /// method is called, for example. |
205 | /// |
206 | /// ## Types with special considerations |
207 | /// |
208 | /// Classes with [lerp] static methods typically have corresponding dedicated |
209 | /// [Tween] subclasses that call that method. For example, [ColorTween] uses |
210 | /// [Color.lerp] to implement the [ColorTween.lerp] method. |
211 | /// |
212 | /// Types that define `+` and `-` operators to combine values (`T + T → T` and |
213 | /// `T - T → T`) and an `*` operator to scale by multiplying with a double (`T * |
214 | /// double → T`) can be directly used with `Tween<T>`. |
215 | /// |
216 | /// This does not extend to any type with `+`, `-`, and `*` operators. In |
217 | /// particular, [int] does not satisfy this precise contract (`int * double` |
218 | /// actually returns [num], not [int]). There are therefore two specific classes |
219 | /// that can be used to interpolate integers: |
220 | /// |
221 | /// * [IntTween], which is an approximation of a linear interpolation (using |
222 | /// [double.round]). |
223 | /// * [StepTween], which uses [double.floor] to ensure that the result is |
224 | /// never greater than it would be using if a `Tween<double>`. |
225 | /// |
226 | /// The relevant operators on [Size] also don't fulfill this contract, so |
227 | /// [SizeTween] uses [Size.lerp]. |
228 | /// |
229 | /// In addition, some of the types that _do_ have suitable `+`, `-`, and `*` |
230 | /// operators still have dedicated [Tween] subclasses that perform the |
231 | /// interpolation in a more specialized manner. One such class is |
232 | /// [MaterialPointArcTween], which is mentioned above. The [AlignmentTween], and |
233 | /// [AlignmentGeometryTween], and [FractionalOffsetTween] are another group of |
234 | /// [Tween]s that use dedicated `lerp` methods instead of merely relying on the |
235 | /// operators (in particular, this allows them to handle null values in a more |
236 | /// useful manner). |
237 | /// |
238 | /// ## Nullability |
239 | /// |
240 | /// The [begin] and [end] fields are nullable; a [Tween] does not have to |
241 | /// have non-null values specified when it is created. |
242 | /// |
243 | /// If `T` is nullable, then [lerp] and [transform] may return null. |
244 | /// This is typically seen in the case where [begin] is null and `t` |
245 | /// is 0.0, or [end] is null and `t` is 1.0, or both are null (at any |
246 | /// `t` value). |
247 | /// |
248 | /// If `T` is not nullable, then [begin] and [end] must both be set to |
249 | /// non-null values before using [lerp] or [transform], otherwise they |
250 | /// will throw. |
251 | /// |
252 | /// ## Implementing a Tween |
253 | /// |
254 | /// To specialize this class for a new type, the subclass should implement |
255 | /// the [lerp] method (and a constructor). The other methods of this class |
256 | /// are all defined in terms of [lerp]. |
257 | class Tween<T extends Object?> extends Animatable<T> { |
258 | /// Creates a tween. |
259 | /// |
260 | /// The [begin] and [end] properties must be non-null before the tween is |
261 | /// first used, but the arguments can be null if the values are going to be |
262 | /// filled in later. |
263 | Tween({ |
264 | this.begin, |
265 | this.end, |
266 | }); |
267 | |
268 | /// The value this variable has at the beginning of the animation. |
269 | /// |
270 | /// See the constructor for details about whether this property may be null |
271 | /// (it varies from subclass to subclass). |
272 | T? begin; |
273 | |
274 | /// The value this variable has at the end of the animation. |
275 | /// |
276 | /// See the constructor for details about whether this property may be null |
277 | /// (it varies from subclass to subclass). |
278 | T? end; |
279 | |
280 | /// Returns the value this variable has at the given animation clock value. |
281 | /// |
282 | /// The default implementation of this method uses the `+`, `-`, and `*` |
283 | /// operators on `T`. The [begin] and [end] properties must therefore be |
284 | /// non-null by the time this method is called. |
285 | /// |
286 | /// In general, however, it is possible for this to return null, especially |
287 | /// when `t`=0.0 and [begin] is null, or `t`=1.0 and [end] is null. |
288 | @protected |
289 | T lerp(double t) { |
290 | assert(begin != null); |
291 | assert(end != null); |
292 | assert(() { |
293 | // Assertions that attempt to catch common cases of tweening types |
294 | // that do not conform to the Tween requirements. |
295 | dynamic result; |
296 | try { |
297 | // ignore: avoid_dynamic_calls |
298 | result = (begin as dynamic) + ((end as dynamic) - (begin as dynamic)) * t; |
299 | result as T; |
300 | return true; |
301 | } on NoSuchMethodError { |
302 | throw FlutterError.fromParts(<DiagnosticsNode>[ |
303 | ErrorSummary('Cannot lerp between " $begin" and " $end".' ), |
304 | ErrorDescription( |
305 | 'The type ${begin.runtimeType} might not fully implement `+`, `-`, and/or `*`. ' |
306 | 'See "Types with special considerations" at https://api.flutter.dev/flutter/animation/Tween-class.html ' |
307 | 'for more information.' , |
308 | ), |
309 | if (begin is Color || end is Color) |
310 | ErrorHint('To lerp colors, consider ColorTween instead.' ) |
311 | else if (begin is Rect || end is Rect) |
312 | ErrorHint('To lerp rects, consider RectTween instead.' ) |
313 | else |
314 | ErrorHint( |
315 | 'There may be a dedicated " ${begin.runtimeType}Tween" for this type, ' |
316 | 'or you may need to create one.' , |
317 | ), |
318 | ]); |
319 | } on TypeError { |
320 | throw FlutterError.fromParts(<DiagnosticsNode>[ |
321 | ErrorSummary('Cannot lerp between " $begin" and " $end".' ), |
322 | ErrorDescription( |
323 | 'The type ${begin.runtimeType} returned a ${result.runtimeType} after ' |
324 | 'multiplication with a double value. ' |
325 | 'See "Types with special considerations" at https://api.flutter.dev/flutter/animation/Tween-class.html ' |
326 | 'for more information.' , |
327 | ), |
328 | if (begin is int || end is int) |
329 | ErrorHint('To lerp int values, consider IntTween or StepTween instead.' ) |
330 | else |
331 | ErrorHint( |
332 | 'There may be a dedicated " ${begin.runtimeType}Tween" for this type, ' |
333 | 'or you may need to create one.' , |
334 | ), |
335 | ]); |
336 | } |
337 | }()); |
338 | // ignore: avoid_dynamic_calls |
339 | return (begin as dynamic) + ((end as dynamic) - (begin as dynamic)) * t as T; |
340 | } |
341 | |
342 | /// Returns the interpolated value for the current value of the given animation. |
343 | /// |
344 | /// This method returns `begin` and `end` when the animation values are 0.0 or |
345 | /// 1.0, respectively. |
346 | /// |
347 | /// This function is implemented by deferring to [lerp]. Subclasses that want |
348 | /// to provide custom behavior should override [lerp], not [transform] (nor |
349 | /// [evaluate]). |
350 | /// |
351 | /// See the constructor for details about whether the [begin] and [end] |
352 | /// properties may be null when this is called. It varies from subclass to |
353 | /// subclass. |
354 | @override |
355 | T transform(double t) { |
356 | if (t == 0.0) { |
357 | return begin as T; |
358 | } |
359 | if (t == 1.0) { |
360 | return end as T; |
361 | } |
362 | return lerp(t); |
363 | } |
364 | |
365 | @override |
366 | String toString() => ' ${objectRuntimeType(this, 'Animatable' )}( $begin \u2192 $end)' ; |
367 | } |
368 | |
369 | /// A [Tween] that evaluates its [parent] in reverse. |
370 | class ReverseTween<T extends Object?> extends Tween<T> { |
371 | /// Construct a [Tween] that evaluates its [parent] in reverse. |
372 | ReverseTween(this.parent) |
373 | : super(begin: parent.end, end: parent.begin); |
374 | |
375 | /// This tween's value is the same as the parent's value evaluated in reverse. |
376 | /// |
377 | /// This tween's [begin] is the parent's [end] and its [end] is the parent's |
378 | /// [begin]. The [lerp] method returns `parent.lerp(1.0 - t)` and its |
379 | /// [evaluate] method is similar. |
380 | final Tween<T> parent; |
381 | |
382 | @override |
383 | T lerp(double t) => parent.lerp(1.0 - t); |
384 | } |
385 | |
386 | /// An interpolation between two colors. |
387 | /// |
388 | /// This class specializes the interpolation of [Tween<Color>] to use |
389 | /// [Color.lerp]. |
390 | /// |
391 | /// The values can be null, representing no color (which is distinct to |
392 | /// transparent black, as represented by [Colors.transparent]). |
393 | /// |
394 | /// See [Tween] for a discussion on how to use interpolation objects. |
395 | class ColorTween extends Tween<Color?> { |
396 | /// Creates a [Color] tween. |
397 | /// |
398 | /// The [begin] and [end] properties may be null; the null value |
399 | /// is treated as transparent. |
400 | /// |
401 | /// We recommend that you do not pass [Colors.transparent] as [begin] |
402 | /// or [end] if you want the effect of fading in or out of transparent. |
403 | /// Instead prefer null. [Colors.transparent] refers to black transparent and |
404 | /// thus will fade out of or into black which is likely unwanted. |
405 | ColorTween({ super.begin, super.end }); |
406 | |
407 | /// Returns the value this variable has at the given animation clock value. |
408 | @override |
409 | Color? lerp(double t) => Color.lerp(begin, end, t); |
410 | } |
411 | |
412 | /// An interpolation between two sizes. |
413 | /// |
414 | /// This class specializes the interpolation of [Tween<Size>] to use |
415 | /// [Size.lerp]. |
416 | /// |
417 | /// The values can be null, representing [Size.zero]. |
418 | /// |
419 | /// See [Tween] for a discussion on how to use interpolation objects. |
420 | class SizeTween extends Tween<Size?> { |
421 | /// Creates a [Size] tween. |
422 | /// |
423 | /// The [begin] and [end] properties may be null; the null value |
424 | /// is treated as an empty size. |
425 | SizeTween({ super.begin, super.end }); |
426 | |
427 | /// Returns the value this variable has at the given animation clock value. |
428 | @override |
429 | Size? lerp(double t) => Size.lerp(begin, end, t); |
430 | } |
431 | |
432 | /// An interpolation between two rectangles. |
433 | /// |
434 | /// This class specializes the interpolation of [Tween<Rect>] to use |
435 | /// [Rect.lerp]. |
436 | /// |
437 | /// The values can be null, representing a zero-sized rectangle at the |
438 | /// origin ([Rect.zero]). |
439 | /// |
440 | /// See [Tween] for a discussion on how to use interpolation objects. |
441 | class RectTween extends Tween<Rect?> { |
442 | /// Creates a [Rect] tween. |
443 | /// |
444 | /// The [begin] and [end] properties may be null; the null value |
445 | /// is treated as an empty rect at the top left corner. |
446 | RectTween({ super.begin, super.end }); |
447 | |
448 | /// Returns the value this variable has at the given animation clock value. |
449 | @override |
450 | Rect? lerp(double t) => Rect.lerp(begin, end, t); |
451 | } |
452 | |
453 | /// An interpolation between two integers that rounds. |
454 | /// |
455 | /// This class specializes the interpolation of [Tween<int>] to be |
456 | /// appropriate for integers by interpolating between the given begin |
457 | /// and end values and then rounding the result to the nearest |
458 | /// integer. |
459 | /// |
460 | /// This is the closest approximation to a linear tween that is possible with an |
461 | /// integer. Compare to [StepTween] and [Tween<double>]. |
462 | /// |
463 | /// The [begin] and [end] values must be set to non-null values before |
464 | /// calling [lerp] or [transform]. |
465 | /// |
466 | /// See [Tween] for a discussion on how to use interpolation objects. |
467 | class IntTween extends Tween<int> { |
468 | /// Creates an int tween. |
469 | /// |
470 | /// The [begin] and [end] properties must be non-null before the tween is |
471 | /// first used, but the arguments can be null if the values are going to be |
472 | /// filled in later. |
473 | IntTween({ super.begin, super.end }); |
474 | |
475 | // The inherited lerp() function doesn't work with ints because it multiplies |
476 | // the begin and end types by a double, and int * double returns a double. |
477 | @override |
478 | int lerp(double t) => (begin! + (end! - begin!) * t).round(); |
479 | } |
480 | |
481 | /// An interpolation between two integers that floors. |
482 | /// |
483 | /// This class specializes the interpolation of [Tween<int>] to be |
484 | /// appropriate for integers by interpolating between the given begin |
485 | /// and end values and then using [double.floor] to return the current |
486 | /// integer component, dropping the fractional component. |
487 | /// |
488 | /// This results in a value that is never greater than the equivalent |
489 | /// value from a linear double interpolation. Compare to [IntTween]. |
490 | /// |
491 | /// The [begin] and [end] values must be set to non-null values before |
492 | /// calling [lerp] or [transform]. |
493 | /// |
494 | /// See [Tween] for a discussion on how to use interpolation objects. |
495 | class StepTween extends Tween<int> { |
496 | /// Creates an [int] tween that floors. |
497 | /// |
498 | /// The [begin] and [end] properties must be non-null before the tween is |
499 | /// first used, but the arguments can be null if the values are going to be |
500 | /// filled in later. |
501 | StepTween({ super.begin, super.end }); |
502 | |
503 | // The inherited lerp() function doesn't work with ints because it multiplies |
504 | // the begin and end types by a double, and int * double returns a double. |
505 | @override |
506 | int lerp(double t) => (begin! + (end! - begin!) * t).floor(); |
507 | } |
508 | |
509 | /// A tween with a constant value. |
510 | class ConstantTween<T> extends Tween<T> { |
511 | /// Create a tween whose [begin] and [end] values equal [value]. |
512 | ConstantTween(T value) : super(begin: value, end: value); |
513 | |
514 | /// This tween doesn't interpolate, it always returns the same value. |
515 | @override |
516 | T lerp(double t) => begin as T; |
517 | |
518 | @override |
519 | String toString() => ' ${objectRuntimeType(this, 'ConstantTween' )}(value: $begin)' ; |
520 | } |
521 | |
522 | /// Transforms the value of the given animation by the given curve. |
523 | /// |
524 | /// This class differs from [CurvedAnimation] in that [CurvedAnimation] applies |
525 | /// a curve to an existing [Animation] object whereas [CurveTween] can be |
526 | /// chained with another [Tween] prior to receiving the underlying [Animation]. |
527 | /// ([CurvedAnimation] also has the additional ability of having different |
528 | /// curves when the animation is going forward vs when it is going backward, |
529 | /// which can be useful in some scenarios.) |
530 | /// |
531 | /// {@tool snippet} |
532 | /// |
533 | /// The following code snippet shows how you can apply a curve to a linear |
534 | /// animation produced by an [AnimationController] `controller`: |
535 | /// |
536 | /// ```dart |
537 | /// final Animation<double> animation = _controller.drive( |
538 | /// CurveTween(curve: Curves.ease), |
539 | /// ); |
540 | /// ``` |
541 | /// {@end-tool} |
542 | /// |
543 | /// See also: |
544 | /// |
545 | /// * [CurvedAnimation], for an alternative way of expressing the sample above. |
546 | /// * [AnimationController], for examples of creating and disposing of an |
547 | /// [AnimationController]. |
548 | class CurveTween extends Animatable<double> { |
549 | /// Creates a curve tween. |
550 | CurveTween({ required this.curve }); |
551 | |
552 | /// The curve to use when transforming the value of the animation. |
553 | Curve curve; |
554 | |
555 | @override |
556 | double transform(double t) { |
557 | if (t == 0.0 || t == 1.0) { |
558 | assert(curve.transform(t).round() == t); |
559 | return t; |
560 | } |
561 | return curve.transform(t); |
562 | } |
563 | |
564 | @override |
565 | String toString() => ' ${objectRuntimeType(this, 'CurveTween' )}(curve: $curve)' ; |
566 | } |
567 | |