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