Ever wish there was an easy way to add rich animation to your Flutter UIs? I did, so when we started working on the Wonderous app, it seemed like the perfect excuse to build a best of breed open-source animation package.
I have an unhealthy obsession with writing animation libraries (see: gTween & TweenJS), so I had a pretty good idea of what I wanted:
- simple, concise, and clean API
- a wide variety of ready-made effects
- scales well from basic fades to complex sequenced effects
- easy to build totally custom animations
- performant, small, and dependency free
- fun! I want to enjoy using it and sharing the results.
Flutter has a powerful animation framework, but it’s also quite verbose. Let’s say I wanted a button to slide in — I’d have to convert my parent widget to a StatefulWidget
, initialize a persistent AnimationController
, ensure it’s properly updated and disposed of, use it to drive a CurvedAnimation
, and feed that into a SlideTransition
wrapping my button.
To make it worse, the necessary code tends to be scattered across 3 or 4 parts of your class, and gets more complex with each additional animated element or effect. This introduces friction and discourages playing with animation.
Flutter Animate abstracts all of this away:
Animate(effects: [SlideEffect()], child: myButton)
It also adds an animate
extension to Widget
, which makes it extra concise (but you can use either syntax interchangeably):
myButton.animate().slide()
And just to make it super extra concise, there’s extensions for num
to declare a Duration
:
myButton.animate().slide(delay: 300.ms, duration: 2.seconds)
Flutter Animate includes a wide variety of pre-built visual effects (fade, slide, scale, rotate, blur, shimmer, shake, saturation, tint, visibility, and more), which have attractive defaults, but are customizable via parameters:
myText.animate().tint(color: Colors.red, end: 0.5)
Layering multiple effects on a single target is simple:
myButton.animate().fadeIn(curve: Curves.easeOut).scale(begin: 0.5)
One other neat trick: subsequent effects inherit their delay
, duration
, and curve
, so your effects synchronize by default. For example, these two effects (fade + slide) will run together:
myText.animate().fade(delay: 300.ms, duration: 700.ms).slide()
You’re not stuck with just the included effects though, it’s super easy to build your own, either as reusable Effect
classes, or via CustomEffect
.
Beyond all that, there’s: toggles, swaps, builders, events, delayed starts, sequenced/parallel effects, saved effects, external controllers, and adapters (which let you sync animation to scrolling or other inputs).
Flutter Animate has a very detailed README, and comprehensive documentation, so we won’t dig into everything here. Instead, let’s take a look at one effect from Wonderous that was a lot of fun to create — the teaser animation for collectable artifacts:
We’re going to jump into the deep end with this one! If it seems a bit tough to grasp, don’t worry, this is probably the most complicated chunk of code I’ve written with the library so far.
collectible.animate(onPlay: (controller) => controller.repeat())
.shimmer(delay: 4000.ms, duration: 1800.ms) // shimmer +
.shake(hz: 4, curve: Curves.easeInOutCubic) // shake +
.scale(begin: 1.0, end: 1.1, duration: 600.ms) // scale up
.then(delay: 600.ms) // then wait and
.scale(begin: 1.0, end: 1 / 1.1) // scale down
The first line creates the animation, and uses the onPlay
callback to tell its AnimationController
to loop continuously.
The next line adds a shimmer
effect, which will start after 4 seconds (delay: 4000.ms
), and run for 1.8 seconds (duration: 1800.ms
).
These timing values are inherited by the subsequent shake
effect, so it will run in parallel. It also adds a curve
, so the shake eases in and out.
The remainder is a bit tricky — I wanted the collectible to scale up, hold for a bit, then scale back down, all in the same time as the shimmy-shake.
The first scale
inherits the 4 second delay, but defines a shorter duration (1800/3 = 600.ms
) so it scales up over the first third of the other effects.
This is followed by then
, which is a special effect that sets the inheritable delay to the end of the previous effect, plus an optional additional delay
. In this case, it makes it so the second scale
starts 600ms after the first one ends.
The second scale
counter-scales (end: 1 / 1.1
) back down over the same 600ms.
Combine this all together, and we have our final effect in just 6 short lines of code. Nice!
Flutter Animate is easy to use, but that also means it’s easy to go overboard and overwhelm or irritate your users — use restraint, be aware of the implications on performance and battery life, and always ask yourself if an animation is making your UI a better experience overall.
If you’d like to learn more about Flutter Animate then check out the in-depth README, API docs or the code.
Better yet, take a look at the open-source Wonderous mobile app, which uses the package for all of its delightful animations, and is available on the iOS and Play stores.
We welcome community participation in the package: logging issues, requesting features, or contributing new effects. It’s super easy to build new effects for Flutter Animate — usually with just a few lines of code. In fact, while playing with ideas for this blog post I wrote a new 3D flip effect (coming soon) in about 20 minutes.
I hope you have fun playing with Flutter Animate, and that it helps bring a bit more life and personality to your apps!
Wonderful, thanks for the post. It’s super informative and helpful. I didn’t know using animation is that simple.
amazing. ehat about expand and collapse animation???
dude this is some seriously awesome stuff!!
@Hesam — you’re welcome!
@santosh — feel free to request it (or better yet, submit a pull request) on GitHub! In fact, this issue may already cover it? https://github.com/gskinner/flutter_animate/issues/10
@JT — thanks! It was a lot of fun to build.
holy crap that’s cool. nice API!
What a powerful package and nice article!
can you make tutorial about how you build wonderous app please it will be a huge thing to learn from the best flutter app .
it’s just amazing! Your promotional video of v2.10 was awesome! now it’s v 4.50