# Animation

## How are animations scheduled?

* `Window.onBeginFrame` invokes `SchedulerBinding.handleBeginFrame` every frame, which runs all transient callbacks scheduled during the prior frame. Ticker instances utilize transient callbacks (via `SchedulerBinding.scheduleFrameCallback`), and are therefore evaluated at this point. All tickers update their measure of elapsed time using the same frame timestamp, ensuring that tickers tick in unison.
* `AnimationController` utilizes an associated `Ticker` to track the passage of time. When the ticker ticks, the elapsed time is provided to an internal simulation which transforms real time into a decimal value. The simulation (typically `_InterpolationSimulation`) interpolates between `AnimationController.lowerBound` and `AnimationController.upperBound` (if spanning the animation’s full range), or `AnimationController.value` and `AnimationController.target` (if traversing from the current value to a new one), applying a curve if available. Listeners are notified once the simulation produces a new value.
* The animation’s behavior (playing forward, playing backward, animating toward a target, etc) is a consequence of how this internal simulation is configured (i.e., by reversing the bounds, by altering the duration, by using a `_RepeatingSimulation` or `SpringSimulation`). Typically, the simulation is responsible for mapping from real time to a value representing animation progress.
  * In the general case, an `_InterpolationSimulation` is configured in `AnimationController._animateToInternal`.
  * Next, the controller’s ticker is started, which advances the the simulation once per frame. The simulation is advanced using the elapsed time reported by the ticker.
  * Listeners are notified whenever the simulation is queried or reaches an endpoint, potentially changing the animation’s status (`AnimationStatus`).
* Composing animations (e.g., via `_AnimatedEvaluation` or `_ChainedEvaluation`) works by proxying the underlying listenable (i.e., by delegating listener operations to the parent animation, which advances as described above).

## What is an animation?

* An animation, as represented by `Animation<double>`, traverses from zero to one (and vice versa) over a user-defined interval (this is typically facilitated by an `AnimationController`, a special `Animation<double>` that advances in real time). The resulting value represents the animation’s progress (i.e., a timing value) and is often fed into a chain of animatables or descendant animations. These are re-evaluated every time the animation advances and therefore notifies its listeners. Some descendants (e.g., curves) transform the animation’s timing value into a new timing value; these affect the animation’s rate of change (e.g., easing) but not its duration. Others produce derived values that can be used to update the UI (e.g., colors, shapes, and sizes). Repeatedly updating the UI using these values is the basis of animation.

## What are the animation building blocks?

* `Animation<T>` couples `Listenable` with `AnimationStatus` and produces a sequence of values with a beginning and an end. The animation’s status is derived from the sequence’s directionality and whether values are currently being produced. In particular, the animation can be stopped at the sequence’s beginning or end (`AnimationStatus.dimissed`, `AnimationStatus.completed`), or actively producing values in a particular order (`AnimationStatus.forward`, `AnimationStatus.reverse`). `Animation<T>` extends `ValueListenable` which produces a sequence of values but does not track status.
  * `Animation<double>` is the most common specialization of `Animation<T>` (and the only specialization that can be used with `Animatable<T>`); as a convention, `Animation<double>` produces values from zero to one, though it may overshoot this range before completing. These values are typically interpreted as the animation’s progress (referred to as timing values, below). How this interval is traversed over time determines the behavior of any downstream animatables.
  * `Animation<double>` may represent other sequences, as well. For instances, an `Animation<double>` might describe a sequence of border radii or line thicknesses.
  * More broadly, `Animation<T>`, where `T` is not a timing value, is devoid of conventional significance. Such animations progress through their values as described earlier, and are typically driven by a preceding `Animation<double>` (that does represent a timing value).
* `Animatable<T>` describes an animatable value, mapping an `Animation<double>` (which ranges from zero to one) to a sequence of derived values (via `Animatable<T>`.evaluate, which forwards the animation’s value to `Animatable<T>.transform` to produce a new value of type `T`). The animatable may be driven by an animation (i.e., repeatedly evaluated as the animation generates notifications, via `Animatable<T>.animate`). It may also be associated with a parent animatable to create an evaluation chain (i.e., the parent evaluates the animation value, then the child evaluates the parent’s value, via `Animatable<T>.chain`). Unless the parent animatable is driven by an animation, however, chaining will not cause the animatable to animate; it only describes a sequence of transformations.
  * `Animatable<T>.evaluate` always maps from a double to a value of type `T`. Conventionally, the provided double represents a timing value (ranging from zero to one), but this is not a requirement.
* Tween is a subclass of `Animatable<T>` that linearly interpolates between beginning and end values of type `T` (via `Tween.lerp`). By default, algebraic linear interpolation is used, though many types implement custom methods (via `T.lerp`) or provide overloaded operators.
  * `TweenSequence` is an animatable that allows an animation to drive a sequence of tweens, associating each with a portion of the animation’s duration (via `TweenSequenceItem.weight`).
* Simulation models an object in one-dimensional space with a position (`Simulation.x`), velocity (`Simulation.dx`), and completion status (`isDone`) using logical units. Simulations are queried using a time value, also in logical units; as some simulations may be stateful, queries should generally use increasing values. A `Tolerance` instance specifies epsilon values for time, velocity, and position to determine when the simulation has settled.
* `AnimationController` is an `Animation<double>` subclass introducing explicit control and frame-synchronized timing. When active, the animation controller is driven at approximately 60 Hz. This is facilitated by a corresponding `Ticker` instance, a synchronized timer that triggers at the beginning of each frame; this instance may change over the course of the controller’s lifespan (via `AnimationController.resync`). The animation can be run backwards and forwards (potentially without bounds), toward and away from target values (via `AnimationController.animateTo` and `AnimationController.animateBack`), or cyclically (via `AnimationController.repeat`). Animations can also be driven by a custom `Simulation` (via `AnimationController.animateWith`) or a built-in spring simulation (via `AnimationController.fling`). The controller’s value (`AnimationController.value`) is advanced in real time, using a duration (`AnimationController.duration`) to interpolate between starting and ending values (`AnimationController.upperBound`, `AnimationController.lowerBound`), both doubles. An immutable view of the animation is also exposed (`AnimationController.view`).
* Ticker invokes a callback once per frame (via a transient callback scheduled using `SchedulerBinding.scheduleFrameCallback`), passing a duration corresponding to how long the ticker has been ticking. This duration is measured using a timestamp set at the beginning of the frame (`SchedulerBinding.handleBeginFrame`). All tickers advance using the same timestamp and are therefore synchronized. When a ticker is enabled, a transient frame callback is registered via `SchedulerBinding.addFrameCallback`; this schedules a frame via `Window.scheduleFrame`, ensuring that the ticker will begin ticking.
  * Tickers measure a duration from when they first tick. If a ticker is stopped, the duration is reset and progress is lost. Muting a ticker allows time (the duration) to continue advancing while suppressing ticker callbacks. The animation will not progress while muted and will appear to jump ahead when unmuted. A ticker can absorb another ticker so that animation progress is not lost; that is, the new ticker will retain the old ticker’s elapsed time.
  * `TickerFuture` exposes the ticker status as a `Future`. When stopped, this future resolves; in all other cases, the future is unresolved. A derivative future, `TickerFuture.orCancel`, extends this interface to throw an exception if the ticker is cancelled.
* `TickerProvider` vends `Ticker` instances. `TickerProviderStateMixin` and `SingleTickerProviderStateMixin` fulfill the `TickerProvider` interface within the context of a `State` object (the latter has less overhead since it only tracks a single ticker). These mixins query an inherited `TickerMode` that can enable and disable all descendent tickers en masse; this allows tickers to be muted and unmuted within a subset of the widget tree efficiently.
* `AnimationLocalListenersMixin` and `AnimationLocalStatusListenersMixin` provide implementations for the two listenable interfaces supported by animations: value listeners (`Animation.addListener`, `Animation.removeListener`), and status listeners (`Animation.addStatusListener`, `Animation.removeStatusListener`). Both store listeners in a local `ObserverList` and support hooks indicating when a listener is registered and unregistered (`didRegisterListener` and `didUnregisterListener`, respectively). A number of framework subclasses depend on these mixins (e.g., `AnimationController`) since `Animation<T>` doesn’t provide a concrete implementation.
  * `AnimationLazyListenerMixin` uses the aforementioned hooks to notify the client when there are no more listeners. This allows resources to be released until a listener is once again added (via `AnimationLazyListenerMixin.didStartListening` and `AnimationLazyListenerMixin.didStopListening`).
  * `AnimationEagerListenerMixin` ignores these hooks, instead introducing a dispose protocol; resources will be retained through the animation’s lifespan and therefore must be disposed before the instance is released.

## How are animations curved?

* Curve determines an animation’s rate of change by specifying a mapping from input to output timing values (i.e., from \[0, 1] to \[0, 1], though some curves stretch this interval, e.g., `ElasticInCurve`). `Animation<double>` produces suitable input values that may then be transformed (via `Curve.transform`) into new timing values. Later, these values may be used to drive downstream animatables (or further transformed), effectively altering the animation’s perceived rate of change.
  * Geometrically, a curve may be visualized as mapping an input timing value (along the X-axis) to an output timing value (along the Y-axis), with zero corresponding to `AnimationStatus.dismissed` and one corresponding to `AnimationStatus.completed`.
  * Curves cannot alter the overall duration of an animation, but will affect the rate that an animation is advanced during that interval. Additionally, even if they overshoot the unit interval, curves must map zero and one to values that round to zero or one, respectively.
  * There are a number of built-in curve instances:
    * Cubic defines a curve as a cubic function.
    * `ElasticInCurve`, `ElasticOutCurve`, `ElasticInOutCurve` define a spring-like curve that overshoots as it grows, shrinks, or settles, respectively.
    * Interval maps a curve to a subinterval, clamping to 0 or 1 at either end.
    * Threshold is 0 until a threshold is reached, then 1 thereafter.
    * `SawTooth` produces N linear intervals, with no interpolation at edges
    * `FlippedCurve` transforms an input curve, mirroring it both horizontally and vertically.
    * Curves exposes a large number of pre-defined curves.
* `CurvedAnimation` is an `Animation<double>` subclass that applies a curve to a parent animation (via `AnimationWithParentMixin`). As such, `CurvedAnimation` proxies the parent animation, transforming each value before any consumers may read it (via `Curve.transform`). `CurvedAnimation` also allows different curves to be used for forward and reverse directions.
* `CurveTween` is an `Animatable<double>` subclass that is analogous to `CurvedAnimation`. As an animatable, `CurveTween` delegates its transform (via `Animatable<double>.transform`) to the provided curve transform (via `Curve.transform`). Since `CurveTween` doesn’t perform interpolation, but instead represents an arbitrary mapping, it isn’t actually a tween.
* `AnimationController` includes built-in curve support (via `_InterpolationSimulation`). When the simulation is advanced to transform elapsed wall time into a timing value (by querying `_InterpolationSimulation.x`), if available, a curve is used when computing the new value. As the resulting value is generally interpreted as a timing value, this influences the perceived rate of change of the animation.

## How are animations composed?

* `AnimationWithParentMixin` provides support for building animations that delegate to a parent animation. The various listener methods (`AnimationWithParentMixin.addListener`, `AnimationWithParentMixin.addStatusListener`) are forwarded to the parent; all relevant state is also read from the parent. Clients provide a value accessor that constructs a derivative value based on the parent’s value.
* Composition is managed via `Animatable.chain` or `Animatable.animate`; `Animation<T>.drive` delegates to the provided animatable.
  * `_AnimatedEvaluation` is an `Animation<T>` that applies an animatable to a parent animation. All listenable methods delegate to the parent animation (via `AnimationWithParentMixin`); thus, the resulting animation is driven by the parent. The value accessor is overwritten so that parent’s value may be transformed by the animatable (via `Animatable.evaluate`).
  * `_ChainedEvaluation` is an `Animatable<T>` that combines a parent animatable with a child animatable. In particular, `_ChainedEvaluation.transform` first evaluates the parent animatable (via `Animatable<T>.evaluate`), then passes this value to the child animatable.
* `CompoundAnimation` is an `Animation<T>` subclass that combines two animations. `CompoundAnimation.value` is overwritten to produce a final value using the first and second animation’s values (via `CompoundAnimation.first`, `CompoundAnimation.next`). Note that `CompoundAnimation` is driven by two animations (i.e., it ticks when either animation ticks), unlike earlier composition examples that drive an animatable using a single parent animation.

## What are the higher level animation building blocks?

* `ProxyAnimation` provides a read-only view of a parent animation that will reflect any changes to the original animation. It does this by proxying the animation listener methods as well as the status and value accessors. Additionally, `ProxyAnimation` supports replacing the parent animation inline; the transition is seamless from the perspective of any listeners.
* `TrainHoppingAnimation` monitors two animations, switching from the first to the second when the second emits the same value as the first (e.g., because it is reversed or moving toward the value more quickly). `TrainHoppingAnimation` utilizes `AnimationEagerListenerMixin` because it relies on the parent animations’ notifications to determine when to switch tracks, regardless of whether there are any external listeners.
* `CompoundAnimation` combines two animations, ticking when either animation ticks (this differs from, e.g., `Animation.animate`, which drives an animatable via an animation). The status is that of the second animation (if it’s running), else the first. The values are combined by overriding the `Animation.value` accessor; the constituent animations are referenced as `CompoundAnimation.first` and `CompoundAnimation.next`, respectively. This animation is lazy -- it will only listen to the sub-animations when it has listeners, and will avoid generating useless notifications.&#x20;
  * `CompoundAnimation` is the basis of `MaxAnimation`, `MinAnimation`, and `MeanAnimation`.
* `AlwaysStoppedAnimation` exposes a constant value and never changes status or notifies listeners.
* `ReverseAnimation` plays an animation in reverse, using the appropriate status and direction. That is, if the parent animation is played forward (e.g., via `AnimationController.forward`), the `ReverseAnimation`’s status will be reversed. Moreover, the value reported by `ReverseAnimation` will be the inverse of the parent’s value assuming a \[0, 1] range (thus, one minus the parent’s value). Note that this differs from simply reversing a tween (e.g., tweening from one to zero); though the values would be reversed, the animation status would be unchanged.

## What are the highest level animation building blocks?

* `AnimatedWidget` is an abstract stateful widget that rebuilds whenever the provided listenable notifies its clients. When this happens, the associated state instance is marked dirty (via `_AnimatedState.setState`) and rebuilt. `_AnimatedState.build` delegates to the widget’s build method, which subclasses must implement; these utilize the listenable (typically an animation) to update the UI.
* `AnimatedBuilder` extends `AnimatedWidget` to accept a build function (`TransitionBuilder`); this builder is invoked whenever the widget rebuilds (via `AnimatedBuilder.build`). This allows clients to utilize the `AnimatedWidget` flow without creating an explicit subclass.

## How does implicit animation work?

* `ImplicitlyAnimatedWidget` provides support for widgets that animate in response to changes to selected properties; the initial value is not animated. Though descendant widgets are only able to customize the animation’s duration and curve, `ImplicitlyAnimatedWidget` are often convenient in that they fully manage the underlying `AnimationController`.
  * Subclasses must use a `State` instance that extends `ImplicitlyAnimatedWidgetState`. Those that should be rebuilt (i.e., marked dirty) whenever the animation ticks extend `AnimatedWidgetBaseState`, instead.
    * `ImplicitlyAnimatedWidgetState.forEachTween` is the engine that drives implicit animation. Subclasses implement this method such that the provided visitor (`TweenVisitor`) is invoked once per implicitly animatable property.
    * The visitor function requires three arguments: the current tween instance (constructed by the superclass but cached locally, e.g., `ExampleState._opacityTween`), the target value (typically read from the widget, e.g., `ExampleState.widget.opacityValue`), and a constructor (`TweenConstructor`) that returns a new tween instance starting at the provided value. The visitor returns an updated tween; this value is typically assigned to the same field associated with the first argument.
    * Tweens are constructed during state initialization (via `ImplicitlyAnimatedWidgetState._constructTweens`) for all implicitly animatable properties with non-null target values (via `ImplicitlyAnimatedWidgetState.forEachTween`). Tweens may also be constructed outside of this context as they transition from null to non-null target values.
    * When the widget is updated (via `ImplicitlyAnimatedWidgetState.didUpdateWidget`), `ImplicitlyAnimatedWidgetState.forEachTween` steps through the subclass’s animatable properties to update the tweens’ bounds (via `ImplicitlyAnimatedWidgetState._updateTween`). The tween’s start is set using the current animation value (to avoid jumping), with the tween’s end set to the target value.
    * Last, the animation is played forward if the tween wasn’t already animating toward the target value (i.e., the tween’s previous endpoint didn’t match the target value, via `ImplicitlyAnimatedWidgetState._shouldAnimateTweens`).
  * The subclass is responsible for using the animation (`ImplicitlyAnimatedWidgetState.animation`) and tween directly (i.e., by evaluating the tween using the animation’s current value).
