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 really neat 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.
We are what we repeatedly do. Excellence, then, is not an act, but a habit. Try out Justly and start building your habits today!
Let’s take a closer look at the features of the library.
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.
This library provides drag-and-drop support for both Listview
and GridView
and allows users to reorder items with animations.
There is built-in support for some animations like ScaleIn, FadeIn, and SizeIn.
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
.
This library is great for larger lists. it optimizes performance by rendering items only when they enter the viewport.
Now, let’s get practical and see how you can use animated_reorderable_list
in your own Flutter project.
Add the following dependency in pubspec.yaml
file.
animated_reorderable_list: <latest version>
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,),
),
),
);
}
Run the app and see how it looks.
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.
Let's see what it looks like,
You can see smooth transitions and fade in animation. It’s because default animations are set to FadeIn
.
Let’s customize it.
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.
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.
Isn't it pretty easy to implement a Reorderable list with animation?
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.
Now, run the app,
// 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!
Happy coding! 🤖✍🏻
In this article, we’ve explored animated_reorderable_list
library and learned how it simplifies the implementation of drag-and-drop functions within both ListView
and GridView
. As you explore, feel free to share any problems you run into, so we can work together to make the library even better.