Flutter’s animation library is really Awesome for creating really complex animations however there are times where you would want to use more subtle animation such as those which occur whenever the user does something in your app.
Today I will talk about one such animation, scrolling animation. I will be covering how to make smooth scrolling animations in Flutter along with a few real world examples.
Making sense of Scrolling Animation
There are two types of Scrolling Animation the first is a normal animation that occurs when the user scroll to a specific place and the second depends on the overall amount of scrolling; the value of the animation depends on how much the user scrolls.
Drive layout based on the scroll position
scrollable widget in Flutter has some sort of controller that implement
ScrollController. In the next example I will use the Controller to read the current scroll offset of the widget then use that value to drive a visual response.
Here is an example of what we will be doing:
Declare the following variables in the
State object /class:
NOTE: This example will work just if you know how many items are in the list .
Next, create the layout :
Time for the controller :
The only interesting part is line 11 where we have the math to calculate the width for the green
Container. We are getting the user’s current offset in the list and dividing it by the total length of the screen. This value is then divided by the height of the items multiplied by the number of items in the list. and finally, you should remove the listeners in dispose method :
This is all the code necessary to implement any type of animation based on the scroll position. However, after I published the article Simon Lightfoot mentioned a better way to do this and even with less code just using
AnimatedBuilder to listen to the
Using this way you don't have to add or remove listeners to the controller.
Trigger Animation based on the scroll events
Imagine a scenario where you want to hide some widgets when the user scrolls up/down with some in/out animations. In this case, you don’t want to check every time the user scrolls instead what you might want is a way to know if the user starts/stopped scrolling.
Luck for us, there is no better widget for this than
NotificationListener. Notification Listener is another widget provided by Flutter which allows you to wrap a
scrollable. It allows us to listen for
ScrollNotifications whenever the
scrollable is scrolled.
Example: Hide widgets(AppBar, FAB, and BottomAppBar) when the user is scrolling and show them when they stop:
Step 1: Setup Layout
appBaris required otherwise you should create your custom
- I used
FittedBoxjust to avoid some scaling issues while animating. Delete it and you will see. that the Icon in the FAB will not scale
Step 2: Setup Animation
The boilerplate is really simple but just to be clear, I am going to use a
Tween(begin: 0.0, end: 50.0) for the animation object and change the hardcoded value of
50.0 in all the previous code to use
And if you are asking why I am using
PreferredSize here the answer is simple you can’t edit the default
AppBar height without making a custom one, and for the
bottomNavigationBar you can use any widget.
Step 3: Listen to Scroll Notifications
NotificationListener of Type
ScrollStartNotification and another one for
Let me explain: If the user starts scrolling then the animation is reversed which means hide the widgets or make them smaller so they will become invisible. If the user stops moving then we show the widgets again by playing the animation.
The previous example is good but it’s not good UI practice. Let’s implement a common UI pattern, a “Showing back-to-top” button for when the user is scrolling down.
In this example, we will do the same Step 1 and 2 from the previous example, however, we will make some changes to step 3:
ScrollUpdateNotification to get the
scrollDelta. This allows us to decide the direction in which the user is scrolling while also making it easier for us to inverse the effect. For example, if you want to show the widget's if the user is scrolling down just inverse the condition from
notification.scrollDelta < 0 to
notification.scrollDelta > 0 and vice versa for the other condition.
If you don’t like this method, an alternative would be to listen to
UserScrollNotification to obtain the
ScrollDirection. If the user stops scrolling you will get a
Important note on ScrollNotification
Don’t drive your layout based on ScrollUpdateNotifications. When the notification is received, the layout phase is already complete. However, you can still do painting effects since painting happens after layout.
Animate dynamic layout using LayoutBuilder
Every scrollable widget in Flutter is built on top of Slivers. When it comes to Slivers, we must use a
CustomScrollView which means you have only one controller for all your slivers. The problem is some sliver behavior is complex and you can't get the right numbers by just using a
For example: SliverAppBar with
floating:true. As an alternative, we can use a
LayoutBuilder to get the box contains or the amount of space available.
Let's try to simulate the next example :
Step 1: Basic Layout
Step 2: use LayoutBuilder
Stack in line 9 with
LayoutBuilder and implement the Builder function. Once you are finished, create two new double as shown in the code below:
Step 3: Animate The Widgets
So for dinner today, you are going to make this:
For this one I will have the full source code linked below along with some notes. Try to attempt this on your own, I look forward to seeing the results.
Note 1: I used the same Setup from the previous example but i have two layers here the first contains the Text and the Icon in the right and the second layer contains the
Note 2: The
CustomPaint contains the majority of the setup: Before the and after the animation crosses 50%, we draw just the line. For the remaining we draw both the
Arc and the
Note 3: it’s just simple math I didn’t use any formula I was just testing to get the right numbers and I think I it can be improved in the future
Finally here is the code source for the last animation this is still a WIP but if you have any suggestions that would be great, see you in the next article 🙋♀️
For more articles don’t forget to follow me and Flutter Community on medium and Twitter.
Check out some of my other articles: https://medium.com/flutter-community/@rahiche
Raouf Rahiche (@raoufrahiche) | Twitter
The latest Tweets from Raouf Rahiche (@raoufrahiche). Embarcadero MVP. الجزائر