Enter tweens. While far from unique to Flutter, they are a delightfully simple concept for structuring animation code. Their main contribution is to replace the imperative approach above with a functional one. A tween is a value. It describes the path taken between two points in a space of other values, like bar charts, as the animation value runs from zero to one.

Tweens are generic in the type of these other values, and can be expressed in Dart as objects of the type Tween<T> :

The jargon lerp comes from the field of computer graphics and is short for both linear interpolation (as a noun) and linearly interpolate (as a verb). The parameter t is the animation value, and a tween should thus lerp from begin (when t is zero) to end (when t is one).

The Flutter SDK’s Tween<T> class is very similar to the above, but is a concrete class that supports mutating begin and end . I’m not entirely sure why that choice was made, but there are probably good reasons for it in areas of the SDK’s animation support that I have yet to explore. In the following, I’ll use the Flutter Tween<T> , but pretend it is immutable.

We can clean up our code using a single Tween<double> for the bar height:

We’re using Tween for packaging the bar height animation end-points in a single value. It interfaces neatly with the AnimationController and CustomPainter , avoiding widget tree rebuilds during animation as the Flutter infrastructure now marks CustomPaint for repaint at each animation tick, rather than marking the whole ChartPage subtree for rebuild, relayout, and repaint. These are definite improvements. But there’s more to the tween concept; it offers structure to organize our thoughts and code, and we haven’t really taken that seriously. The tween concept says,

Animate T s by tracing out a path in the space of all T s as the animation value runs from zero to one. Model the path with a Tween<T> .

In the code above, T is a double , but we do not want to animate double s, we want to animate bar charts! Well, OK, single bars for now, but the concept is strong, and it scales, if we let it.

(You may be wondering why we don’t take that argument a step further and insist on animating data sets rather than their representations as bar charts. That’s because data sets — in contrast to bar charts which are graphical objects — generally do not inhabit spaces where smooth paths exist. Data sets for bar charts typically involve numerical data mapped against discrete data categories. But without the spatial representation as bar charts, there is no reasonable notion of a smooth path between two data sets involving different categories.)

Returning to our code, we’ll need a Bar type and a BarTween to animate it. Let’s extract the bar-related classes into their own bar.dart file next to main.dart :

I’m following a Flutter SDK convention here in defining BarTween.lerp in terms of a static method on the Bar class. This works well for simple types like Bar , Color , Rect and many others, but we’ll need to reconsider the approach for more involved chart types. There is no double.lerp in the Dart SDK, so we’re using the function lerpDouble from the dart:ui package to the same effect.

Our app can now be re-expressed in terms of bars as shown in the code below; I’ve taken the opportunity to dispense of the dataSet field.

The new version is longer, and the extra code should carry its weight. It will, as we tackle increased chart complexity in part two. Our requirements speak of colored bars, multiple bars, partial data, stacked bars, grouped bars, stacked and grouped bars, … all of it animated. Stay tuned.