The basics

To use TweenAnimationBuilder , I set the length of time that I want my animation to take with the duration parameter, and the range of values that I want it to animate between with the… Tween parameter. As the name suggests, a Tween object enables you to specify a range of values that you want to animate between.

The last thing I need to specify is the builder parameter, which returns what my animated widget will look like at a given moment in time. This builder function takes a parameter that is the same type as your Tween values, which basically tells Flutter what the current animation value is at a given moment.

TweenAnimationBuilder in depth

The example code above showed the bare-minimum set of arguments necessary to use TweenAnimationBuilder , but there is a lot more this widget has to offer! For illustration purposes, I created an app for an extremely common use case: illustration of the Doppler effect in space. Okay, it’s a silly use case, but you might want to apply a color filter to an image and animate the changing colors…which is exactly what we’ll be doing in this scenario.

In the Doppler effect, when a star moves away from you in space, the waves of light elongate, making the light shift closer to the red end of the spectrum. This effect is very subtle and not visible to the naked eye, but astronomers use it to determine the velocity of stars and galaxies relative to us.

Consult your local astrophysicist for more details.

In our app we’re going to make this a little less subtle. I have a nice image of a star, and to change its color, I’m going to use the ColorFiltered widget. I apply a blend mode, and tell it to blend orange into the image to make it a little more reddish.

ColorFiltered(

child: Image.asset('assets/sun.png'),

colorFilter: ColorFilter.mode(color, BlendMode.modulate),

)

Next step…animation! There isn’t a built-in widget that applies an arbitrary color filter to a widget, but we can build one ourselves with TweenAnimationBuilder . To change the color over time, we want to modify the color that we’re applying to the filter. So that’s the value that we’ll animate. We’ll put the ColorFiltered widget inside the builder function of the TweenAnimationBuilder . As I mentioned before, a Tween is just the range of values that we are animating between. In this case, we’ll use a ColorTween to animate between white, which is as if we had no filter, and orange. And there you have it! A nicely animated color filter in 10 lines of code.

TweenAnimationBuilder(

tween: ColorTween(begin: Colors.white, end: Colors.red),

duration: Duration(seconds: 2),

builder: (_, Color color, __) {

return ColorFiltered(

child: Image.asset('assets/sun.png'),

colorFilter: ColorFilter.mode(color, BlendMode.modulate),

);

},

)

Depending on what you want to animate though, your Tween can specify ranges between things other than colors or numbers. You can have a Tween with Offset objects to animate the change of a widget’s position, or you can even animate how the border of a widget changes! The point is you have a ton of options.

Tweens are mutable, so if you know that you’re always going to animate between the same set of values, it’s best to declare your Tween as a static final variable in your class. That way, you don’t create a new object every time you rebuild.

Dynamically modifying Tween values

The previous example showed a really simple way to animate from one value to another without using setState or anything. But, you can do more with TweenAnimationBuilder by dynamically modifying your Tween value.

I changed the code to also include a Slider widget. Then I declared a local variable called _newColor that takes the slider value and converts it to a color. _newColor is also used as the end value in my Tween . Now the animation updates every time I drag the slider.

One thing to keep in mind is that TweenAnimationBuilder always moves from the current value to the new end value. That means as I drag the slider, I see the color change relative to its previous color, rather than always animating from white at the very beginning. Just by setting a new end value to my Tween , I can reverse my animation or move to any point in between. TweenAnimationBuilder always smoothly animates between its current value and the new end point. As you can perhaps infer, this means dynamically changing the start of your Tween has no effect.

onEnd and child

There are a few other parameters that I haven’t talked about yet. The first one is the curve, to describe how we should transition between the beginning and end values in our Tween range. In the previous article we talked about how you can even create a custom curve, but there are a lot of great predefined options too.

The second one is a callback you can specify, so you can do something when the animation completes. Perhaps you want to make another widget appear after this animation finishes. You can also use this callback as a way to reverse your animation back and forth. I recommend that you think carefully before doing this though. The callback makes the type of animation you’re trying to do less clear because the value setting is distributed through your code. Because the values are discontinuous (jumping back to the start again), if you want a repeating animation you’ll need some sort of explicit animation: either a built-in explicit animated widget or extending AnimatedWidget .

There’s one last parameter we haven’t discussed yet: the child parameter. Setting the child parameter is a potential performance optimization. Even though the color changes, the star image widget itself stays the same. As it’s currently written though, that image widget gets reconstructed every time that builder method gets called. We can build that star image ahead of time by passing it in as a child parameter. This way, Flutter knows the only widget that it needs to rebuild from frame to frame is the new color filter, not the star image itself. This example is simple so there’s really no noticeable difference. But, if we were animating a much more complex component, you can imagine performance optimization might become more important.