How to Achieve Effortless List Item Animation and Reordering in Flutter

·

5 min read

How to Achieve Effortless List Item Animation and Reordering in Flutter

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, 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! 🤖✍🏻

Did you find this article valuable?

Support Canopas's blog by becoming a sponsor. Any amount is appreciated!