The Magic of Flutter’s Animated List

Nash
Flutter Community
Published in
6 min readSep 28, 2018

Flutter provides some really nice scrollable widgets out of the box such as ListView, GridView, CustomScroll view etc, but what if you want to animate your content as they enter or leave the list? How would one achieve this?

Well the answer, Animated List.

Animated List

AnimatedList is a widget Flutter provides out of the box for animating items as they are added or removed. This widget is similar in structure to ListView.builder in the sense that both widgets have options for the initial item count as well as a builder for constructing the widgets. In fact, if you look at the build method for AnimatedList, it returns a ListView.builder.

Listed below the constructor of AnimatedList. It shows the different parameters which can be supplied to the list.

Now that you’ve been introduced, how does one use it?

To use this list, you must first start by creating a GlobalKey of type AnimatedListState. This key serves as the medium through which you can interact with the list.

Once you have created the key, you can now pass it to the AnimatedList.

From the above snippet, you may also notice the builder. The builder of AnimatedList is very similar to that of ListView.builder except for one small difference, the extra Animation parameter. This animation runs every time the builder is called.

Setup

Before we could add and remove items, we need some data to play with. In this demo, we are going to keep it very simple and have a list which contains some dummy users. The User is going to be a small model which has a person's first name, last name and a URL for their picture.

With our model and list of test users created, let’s move onto adding them to the AnimatedList.

First, the basic skeleton of the app. We are going to have a StatefulWidget which returns a Scaffold. The Scaffold is going to have an appBar and a body which contains our AnimatedList

For this demo, we are going to have a user fade in when they are added. In our AnimatedList, we create a ListTile and wrap it in a FadeTransition. The animation from the builder is then passed to the FadeTransition for its opacity.

Adding Items

With the basic structure built, let’s move out attention to adding items to the list.

For this, we are going to create a new function addUser(). This function is going to handle the adding of users to our listData as well as inserting an item into the AnimatedList. An important thing to note is we don't add an item to the AnimatedList, we add them to our data. Instead, we tell the AnimatedList to insert a new item at an index.

The above code shows how to add a new user. With an AnimatedList, you can insert at any index. In this case, we are adding at the end of the list so we use listData.length.

To add a new user to our listData we use the add of List.

With the list updated, we need to update our AnimatedList so that we can see the animation and the new user on the screen. For this, we need to use the _listKey for interacting with the list.

To insert the user into the list, call _listKey.currentState.insertItem() and pass it both the index into which you want to insert the new user and the duration of the animation.

Finally we set the addUser() to the IconButton onPressed

Removing Items

Now that we’ve covered how to add an item, it is time to wire our function to remove them.

An important thing to note about removing an item in AnimatedList is the item is immediately removed from the list however it will remain visible on screen for the duration of time specified. Once removed, its index will no longer be passed to AnimatedList.builder.

Before we can actually remove an item, let’s clean up our current code. We will start by changing the way our item is built. Instead of building it directly, let’s create a new function _buildItem(). This function will be responsible for building our ListTile.

Notice our function has two parameters one of which is optional. The reason for this will become clear as we continue. Also take note of the ValueKey around our ListTile. Since our widgets are cached by Flutter, we need a way to uniquely identify them.

At this point, running our code will cause a crash. This is because ValueKey uses the == operator to compare widgets. Since we are using a custom type, we need to override the == operator and hashCode for our UserModel. If you are using InteliJ, you can use Alt+Ins in UserModel and select "generate == and hashCode". Select all three fields and hit “ok”.

Now with our refactoring complete, let’s move on to our delete function. From the code we refactored you may have noticed that we changed our onLongPressed to use a function deleteUser. Let us now create this function.

The above snippet shows the function for removing an item from this list. Fist, the index of the item we want to remove is passed to the function as a parameter. Next, we remove it from our listData. At this point, the item is removed however it is still visible on screen because we did not remove it from our AnimatedList. To do this, we use _listKey.currentState.removeItem().

The method removeItem has three parameters, index, builder and an optional parameter duration. When this method is called, it starts a reversed animation that is passed to builder. This allows us to animate the item off-screen. For this example, we are going to both a FadeTransition and SizeTransition.

As a user is deleted, it is first going to fade then shrink as it is animated off-screen. As the above snippet shows, we are storing the result of listData.removeAt(index); in a local variable user. Next we are removing it from our AnimatedList using _listKey.currentState.removeItem(). We give the method the index which was passed into the function then create our builder. Here we create the build function consisting of BuildContext and Animation<double>. It returns a FadeTransition which has a child of SizeTransition. For the opacity of our fade, we are using a CurvedAnimation consisting of an Interval and a parent of animation. The same is done with SizeTransition only this time the child is our _buildItem(). You may have noticed that we pass our local user variable over to _buildItem(). This is done because the removed item needs to be the same as the one which was on our list. The final piece of our puzzle is duration. This is the length of time we want our animation to run for. In this example, we are using 600 milliseconds.

Results

Assuming you’ve followed along, your final code show look a little something like this:

Running the above code on device yields the following results:

Conclusion

I hoped you enjoyed this article, if you have any questions or spot any errors or simply have a suggestion for an article, please leave a comment or reach out to me on Twitter, I am @Nash0x7E2. The full source code for this project can be found on my GitHub: https://github.com/Nash0x7E2/animated-list-demo. Also be sure to follow Flutter Community to keep up with everything as they relate to Flutter.

— Nash

--

--

Nash
Flutter Community

Leading DevRel @getstream_io 🥑 · Editor and Admin @flutter-community 💙