Adding Micro-Interactions With AnimatedSwitcher
Learn how to add micro-interactions to your Flutter app using AnimatedSwitcher. By Alejandro Ulate Fallas.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Adding Micro-Interactions With AnimatedSwitcher
15 mins
Adding a Second AnimatedSwitcher
Press Skip a few times. You’ll notice the transition of the text looks great, but the images displayed in the background are just jumping into existence. It would be nice if there was a way to animate them too… Oh, wait, there is — another AnimatedSwitcher
!
Open lib/presentation/widgets/image_background.dart. Then, replace child
under // TODO: Replace Image with an AnimatedSwitcher
with the following code:
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 500),
child: Image.network(
imageUrl,
key: ValueKey(imageUrl),
fit: BoxFit.cover,
),
),
You just added animation to the image widget the same way you did QuoteDisplay
earlier, nothing new.
Look at the result. Build and run, if you haven’t already:
Wait, what just happened? The animation is running fine but the Image
widget is no longer extending to the borders. Fear not, you shall fix this soon. :]
Adjusting the Background
OK, you just added a second AnimatedSwitcher
, but now the background image isn’t extending properly. So, what happened to the widgets? Well, it turns out that the way AnimatedSwitcher
builds the layout is affecting child
, which in this case is the background image. Below is the default implementation that AnimatedSwitcher
uses:
static Widget defaultLayoutBuilder(Widget? currentChild, List previousChildren) {
return Stack(
children: [
...previousChildren,
if (currentChild != null) currentChild,
],
alignment: Alignment.center,
);
}
As you can see, AnimatedSwitcher
uses Stack
to show the widgets that transition from one to another, placing currentChild
— if there is one — on the top, visible always.
So, what’s happening right now on Quotine? Well, by default Stack
uses StackFit.loose
as the value for fit
. This affects the Image
widget you use for the background. To fix that, you’ll use a property from AnimatedSwitcher
called layoutBuilder
.
Add the following code to the background image’s AnimatedSwitcher
:
layoutBuilder: (currentChild, previousChildren) {
return Stack(
children: [
...previousChildren,
if (currentChild != null) currentChild,
],
fit: StackFit.expand,
);
},
With this custom implementation of layoutBuilder
, you’re basically recreating the effect provided by defaultLayoutBuilder
with a couple small changes:
- First, you’re using
fit: StackFit.expand
to forceStack
‘s children to expand as much as they can, which in this case is the whole screen. - Then, since the children are expanding,
alignment
is no longer necessary. This makes the widgets expand to the boundaries ofAnimatedSwitcher
, and thus, solves the bug you had with the background.
Build and run with the changes. It’ll look like this:
Discovering Transitions
Now, what if you wanted to customize not only the layout of AnimatedSwitcher
but also the transition between the widgets? Well, there is a way: by using transitionBuilder
.
Look at the default implementation AnimatedSwitcher
uses for transitionBuilder
:
static Widget defaultTransitionBuilder(Widget child, Animation animation) {
return FadeTransition(
opacity: animation,
child: child,
);
}
By default, AnimatedSwitcher
uses the built-in explicit animation FadeTransition
, so you can simply change it to use ScaleTransition
instead. You could even make custom Tween
animations with the animation
parameter provided. Tween
is a linear interpolation useful for interpolating across a range. How about you give that last idea a try. Ready?
Add transitionBuilder
to AnimatedSwitcher
with the following code:
transitionBuilder: (child, animation) {
// 1.
final offsetAnimation = Tween(
begin: const Offset(1.0, 0.0),
end: const Offset(0.0, 0.0),
).animate(animation);
// 3.
return ClipRect(
// 2.
child: SlideTransition(
position: offsetAnimation,
child: child,
),
);
},
Here’s an explanation of what the code you just added means:
- You added a
Tween
animation to handle the explicitSlideTransition
that you’ll use for changing between images.begin
sets the initial position of the widget andend
sets the final position of the widget. Then, you calledanimate
passinganimation
as a parameter. This gets yourTween
ready for use. - Then, you wrapped
child
to be rendered withSlideTransition
and set its position explicitly. This helpsSlideTransition
figure out where to paint your widgets. - Finally, you also wrapped
SlideTransition
with aClipRect
widget. This is so the child isn’t shown when it’s out of frame.
It’s important to remember that the transition is used both with the widget entering and the widget exiting, by running the animation in reverse.
Build and run your app to see the results. Here’s how it’ll look:
Learning About Curves
You’re almost done adding micro-interactions to Quotine, and it’s already looking like a completely different app than when you started — great work! But there’s one last thing you’ll learn about before releasing the new version of the app, and that’s Curves
.
When you’re adding animations to an app, you have to think of real-world behaviors for the different objects you’re animating. If you’re trying to add a ball bouncing up and down, you have to think of the effect gravity has on it. For example, if the ball is heavy, each bounce will be significantly smaller, and you might also see that with each bounce the ball gets slower. Here’s a regular bouncing animation:
In the example above, the effect of going up and down is an animation effect. You can apply a number of effects to animations to make them visually interesting. You usually apply them using curves to influence how the animation behaves. The basic bouncing animation above uses an easeOutExpo
curve when the ball is going upward and easeInExpo
when the ball is going downward.
You can see all the available Curve
implementations in the Curves
API documentation. You have at least 38 different options to choose from, so choose wisely!
Customizing With Curves
OK, you know about Curves
. Cool. But how do you implement them with AnimatedSwitcher
, you ask?
AnimatedSwitcher
has two properties for this: switchInCurve
, which is the animation curve to use when transitioning in a new widget; and switchOutCurve
, which is the animation curve to use when transitioning a previous widget out. It’s very similar to the bouncing ball example you saw in the previous section.
Apply the knowledge you just gathered about curves to customize the way the transitions behave.
Next, add switchInCurve
for AnimatedSwitcher
in lib/presentation/widgets/image_background.dart, which looks like this:
switchInCurve: Curves.easeOutExpo,
Then, add switchOutCurve
for AnimatedSwitcher
in lib/presentation/pages/home_page.dart like this:
switchOutCurve: Curves.easeInExpo,
Here’s what the final result will look like:
Awesome job! You just added micro-interactions to Quotine — you’re definitely a rock star!