Skip to content

Instantly share code, notes, and snippets.

@Nash0x7E2
Created September 27, 2018 00:11
Show Gist options
  • Save Nash0x7E2/38f2775cd5b209ca3cd7d6c5e44132d2 to your computer and use it in GitHub Desktop.
Save Nash0x7E2/38f2775cd5b209ca3cd7d6c5e44132d2 to your computer and use it in GitHub Desktop.

Quick Tip: Animated List


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.

https://gist.github.com/b1912c4b3e757b080a5c6d3f7ee0268b


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.

https://gist.github.com/16d4b7640aa1e93cab097db94e488655

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

https://gist.github.com/6d3d1662d97e972797e60f6b0cd720bd

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.

https://gist.github.com/c5de15b576eeb794d2ab82d1a5c52e23

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

https://gist.github.com/a1cb604177ad82c6a5c86f0c9442ac1f

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.

https://gist.github.com/d00775708675dad089b75002b2aa082c

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

https://gist.github.com/68d0066f56c72464830f629114414da5

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.

https://gist.github.com/f980e59148957d7125d53f82bae96e8c

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 idefify 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.

https://gist.github.com/09deba2ecebb8be7b45304282668d17d

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.

https://gist.github.com/41666b011ac1e1a85bf034f4898eb419

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:

https://gist.github.com/8b2151ffc0fcb6df1da81011e0ae1929

Running the above code on device yields the following results:

YouTube Video

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. Also be sure to follow Flutter Community to keep up with everything as they relate to Flutter.

-- Nash

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment