How to Achieve Effortless List Item Animation and Reordering in Flutter
Nandani Sharma
Posted on March 1, 2024
Background
In a world full of Flutter app creation, making things easy and fun for users is super important.
Recently, I needed to create a list where you could drag items around, and I wanted it to look cool with smooth animations. The built in ReorderableList
of Flutter is good, but it lacked the fancy animations I was hoping for.
Well, the animated_reorderable_list
library is designed to elevate user experience by providing drag-and-drop functionality with some elegant animations to make your app more lively.
In this article, we’ll explore animated_reorderable_list
and will see how easy it is to add animations with the drag-and-drop function for both Listview
and GridView
.
What we’ll implement in this blog?
You can find the full source code here and the library on pub.dev.
Key Features
Let’s take a closer look at the features of the library.
Smooth Transition- In Flutter AnimatedList, While inserting or removing items, the below items jump instead of making a smooth transition. So, this library provides a smooth transition while adding or removing items.
Drag and Drop- This library provides drag-and-drop support for both Listview and GridView and allows users to reorder items with animations.
Built-in Animation Support- There is built-in support for some animations like ScaleIn, FadeIn, and SizeIn.
Simple Implementation- In Flutter AnimatedList, updating the UI requires calling insertItem and removeItem methods through listState using a key. With this library, You can update the UI by just updating a list like ListView.
Enhanced Performance- This library is great for larger lists. it optimizes performance by rendering items only when they enter the viewport.
How to Implement?
Now, let’s get practical and see how you can use animated_reorderable_list
in your own Flutter project.
Add Dependency
Add the following dependency in pubspec.yaml
file.
animated_reorderable_list: <latest version>
Getting Started
This is a simple Todo app where we are going to implement animations while adding or removing items from the list.
For simplicity, we will not implement UI from scratch. You can find the full source code here.
class ActivityPage extends StatefulWidget {
const ActivityPage({super.key});
@override
State<ActivityPage> createState() => _ActivityPageState();
}
class _ActivityPageState extends State<ActivityPage> {
....
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
....
),
body: ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: activities.length,
itemBuilder: (BuildContext context, int index) {
final activity = activities[index];
return ActivityCard(
activity: activity.activity,
why: activity.why,
color: Colors.primaries[index % Colors.primaries.length].shade50,
selected: activity.selected,
onChanged: (value) => _handleOnChanged(value, activity),
);
},
),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.orangeAccent,
onPressed: _displayDialog,
child: const Icon(Icons.add, color: Colors.black,),
),
),
);
}
Implement Animations
Now, we are going to use the AnimatedListView, to implement animations while adding or removing the item from the list.
class _ActivityPageState extends State<ActivityPage> {
....
@override
Widget build(BuildContext context) {
return SafeArea(
....
//Replace Listview.builder with AnimatedList
body: AnimatedListView(
padding: const EdgeInsets.all(16),
//Pass List of items to be displayed
items: activities,
itemBuilder: (BuildContext context, int index) {
final activity = activities[index];
return ActivityCard(
key: Key(activity.activity), //Add unique Key for each item
activity: activity.activity,
why: activity.why,
color: Colors.primaries[index % Colors.primaries.length].shade50,
selected: activity.selected,
onChanged: (value) => _handleOnChanged(value, activity),
);
},
),
....
),
);
}
....
}
Here, we just Replaced ListView.builder with AnimatedListView
. It takes a list of items and itemBuilder function to build each item in the list. We have to pass a key to uniquely identify each item.
Customizing Animations
AnimatedListView(
padding: const EdgeInsets.all(16),
items: activities,
itemBuilder: (BuildContext context, int index) {
....
},
enterTransition: [
FadeIn(
duration: const Duration(
seconds: 2,
),
),
ScaleIn(duration: const Duration(seconds: 2), curve: Curves.bounceIn),
],
exitTransition: [SlideInLeft()],
),
enterTransition:
Specifies the enter tradition for items when they are added to the list.
exitTransition:
Specifies the exit tradition for items when they are removed from the list.
Here we can add a List of animations that run concurrently, However, for customizations such as introducing delays, extending animation duration, or sequencing animations after one another, we can customize animation also.
One thing, we keep in mind is that if we add insertDuration or removeDuration then it will override the duration of a specific animation.
Implement Drag to Reorder
Now, let’s implement drag to reorder. For that, we can use ReorderableAnimatedListView
which supports both drag and drop and animations.
body: AnimatedReorderableListView(
padding: const EdgeInsets.all(16),
items: activities,
itemBuilder: (BuildContext context, int index) {
....
},
onReorder: (int oldIndex, int newIndex) {
setState(() {
final activity = activities.removeAt(oldIndex);
activities.insert(newIndex, activity);
});
},
....
),
We’ve replaced AnimatedListView with AnimatedreorderableListView and add onReorder callback to reorder the items in the list.
Animated Reorderable Gridview
Let’s add it for GridView. AnimatedGridview is similar to AnimatedListView and AnimatedReorderableGridView is similar to AnimatedReorderableListview.
body: AnimatedReorderableGridView(
padding: const EdgeInsets.all(16),
items: activities,
itemBuilder: (BuildContext context, int index) {
....
},
sliverGridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2
),
onReorder: (int oldIndex, int newIndex) {
setState(() {
final activity = activities.removeAt(oldIndex);
activities.insert(newIndex, activity);
});
},
...
),
Here, AnimatedReorderableGridView is similar to created above, but it takes sliverGridDelegate to configure the layout of the grid.
Customize Builder
// A custom builder that is for inserting items with animations.
insertItemBuilder: (Widget child, Animation<double> animation) {
return ScaleTransition( scale: animation, child: child);
},
// A custom builder that is for removing items with animations.
removeItemBuilder: (Widget child, Animation<double> animation){
return ScaleTransition(scale: animation, child: child);
},
insertItemBuilder
and removeItemBuilder
are used as custom builders for inserting and removing items from the list.
It takes two parameters — child
, which is the widget being inserted or removed, and animation
, an animation controller for the animation.
Well, now you may be thinking that it’s pretty easy, right? I bet it is!
Conclusion
With features like smooth transitions, built-in animation support, and optimized performance for larger lists, this library revolutionizes how users interact with your app.
Discover the full article brimming with captivating insights and dynamic animation implementations over at our Canopas blog!
As always, feedback and suggestions are very welcome, please leave them in the comment section below if any.
Happy coding! 🤖✍🏻
Posted on March 1, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
September 16, 2023