Open In App

AnimatedList Flutter

Last Updated : 08 Jun, 2025
Summarize
Comments
Improve
Suggest changes
Share
Like Article
Like
Report

AnimatedList in Flutter is a dynamic list component that enables us to insert and remove elements dynamically. AnimatedList is a list that animates the items when they are removed or inserted, enhancing the user experience.

As we all use ListView in Flutter lists are used for displaying a collection of items in a scrollable list format. In Real-Life scenarios, we sometimes need to add or remove items from the list. This sudden change in the list may confuse the user and lead to a bad user experience. The potential solution for this is to use AnimatedList in Flutter.

Prerequisites

  • Globalkey: GlobalKey is a type of key that is unique across the entire app.
  • ListView: It is a commonly used scrollable list of widgets in Flutter. It displays its children one after another in a scroll direction. It's especially useful when you're not sure how many widgets you'll be displaying, or if you're loading more data in real time.
  • Animations: You need a basic understanding of animations. Animations like SizeTransition, FadeTransition, SlideTransition, etc.

Constructor of the AnimatedList Class

AnimatedList AnimatedList({
Key? key,
required Widget Function(BuildContext, int, Animation<double>) itemBuilder,
int initialItemCount = 0,
Axis scrollDirection = Axis.vertical,
bool reverse = false,
ScrollController? controller,
bool? primary,
ScrollPhysics? physics,
bool shrinkWrap = false,
EdgeInsetsGeometry? padding,
Clip clipBehavior = Clip.hardEdge,
})

Properties of AnimatedList Widget

Property

Description

itemBuilder

It is Required Function that builds each items in list. It is called once for each item and during any animation affecting the item.

initialItemCount

It is used to specify the initial length of the list. It indicates that the number of items that list will start.

scrollDirection

It is used to specify the axis along with the scrolling occurs. It takes a value of Axis type, which can be either Axis.horizontal or Axis.vertical.

reverse

It is Boolean that specify whether the list should display its items in reverse order.

controller

It is used to control position to which scroll view is scrolled.

primary

It is Boolean that determines whether the widget is primary scroll view associated with parent PrimaryScrollController.

physics

It is used to determine how list should respond to user input and how it should over scroll. It takes Object of class that extends ScrollPhysics.

shrinkWrap

Is Boolean that determines whether the scroll view should shrink-wrap its content.

padding

It is used to provide padding to the AnimatedList. Takes EdgeInsets Object which defines padding.

clipBehavior

It is used to control how the widget should clip it's children. It takes a value from the Clip enum.

Simple Example of AnimatedList

In this example we are going to display list of persons using AnimatedList. Person will be having Name and Designation. we will first create a model and then using this create list of persons. Later we will be using this to display to user. user also can delete the items in list.

Step 1: Create a new Flutter Application

Create a new Flutter application using the command Prompt. To create a new app, write the below command and run it.

flutter create app_name

To know more about it refer this article: Creating a Simple Application in Flutter.

Step 2: Folder Structure

Follow below folder structure for better code organization.

folder_structure

Step 3: Create a model

Create Person Model for creating list of persons. This list is further used to diplay infomation in the form of List. Person Model is simple class with properties and Constructor.

Person.dart:

Person.dart
class Person {
  final String name;
  final String designation;

  Person(this.name, this.designation);
}


Step 4: Modify the main() function in codebase

we are modifying the main() function as per our need .

Dart
// Importing the Flutter Material package for UI components
import 'package:flutter/material.dart';
// Importing a custom model class for Person data structure
import 'package:flutter_geeks/models/Person.dart';

// Entry point of the Flutter application
void main() {
  runApp(const MyApp()); // Runs the app starting from MyApp widget
}

// Root widget of the application, which doesn't hold state
class MyApp extends StatelessWidget {
  const MyApp({super.key}); // Constructor with optional key

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Geeks', // App title
      theme: ThemeData(primarySwatch: Colors.green), // Global theme
      home: const MainListScreen(), // Main screen widget
      debugShowCheckedModeBanner: false, // Removes debug banner
    );
  }
}

In the main() function, runApp() function is called which is taking the home as MyApp(). debugShowCheckedModeBanner is set to false , it will disable the debug banner from the app.

MyApp is a stateless widget which is returning MainListScreen widget.

Step 5: Create the MainListScreen Widget

This stateful widget that returns a new instance of _MainListScreenState when its createState mathod is called.

Dart
import 'package:animated_list_example/models/Person.dart';
import 'package:flutter/material.dart';

class MainListScreen extends StatefulWidget {
  const MainListScreen({super.key});

  @override
  State<MainListScreen> createState() => _MainListScreenState();
}

class _MainListScreenState extends State<MainListScreen> {
   @override
  Widget build(BuildContext context) {
    return Scaffold();
  }
}


Step 6: Defining the GlobalKey and person list

Dart
final GlobalKey<AnimatedListState> _listKey = GlobalKey<AnimatedListState>();
  List<Person> people = [];


GlobalKey<AnimatedListState> is defined to keep reference to AnimatedListState and List<Person> to store the list of people.

Step 7: Define Add Person Method

Dart
// Function to add a new Person to the list
void _addPerson(personName, personDesignation) {
    people.add(Person(personName, personDesignation)); // Add to list
    _listKey.currentState!.insertItem(
        people.length - 1, // Insert at end
        duration: const Duration(milliseconds: 1000), // Animation duration
    );
}

This method takes a person's name and designation as arguments, creates a new Person object, adds it to the people list, and inserts it into the AnimatedList.

Step 8: Define remove person method

Dart
// Function to remove a Person from the list by index
void _removePerson(int index) {
 _listKey.currentState!.removeItem(
  index, // Remove from list at index
  (context, animation) => SizeTransition(
    sizeFactor: animation, // Animate shrinking
    child: const Card(
      margin: EdgeInsets.all(10),
      color: Colors.red,
      child: ListTile(
        title: Text(
          "Deleted",
          style: TextStyle(
            fontSize: 20,
            fontWeight: FontWeight.bold,
            color: Colors.white,
          ),
        ),
      ),
    ),
  ),
  duration: const Duration(milliseconds: 500), // Removal animation
 );
 people.removeAt(index); // Remove from data list
}

This method takes an index as an argument, removes the person at that index from the AnimatedList and the people list.

Step 9: Override the InitState() method

Dart
// Called when the widget is inserted into the widget tree
@override
void initState() {
    WidgetsBinding.instance.addPostFrameCallback((_) {
        // Pre-populating the list with dummy people
        _addPerson('Ram', 'Web Developer');
        _addPerson('Abhi', 'Software Engineer');
        _addPerson('Anu', 'Software Engineer');
        _addPerson('Sita', 'Data Scientist');
        _addPerson('Raj', 'DevOps Engineer');
    });
    super.initState();
}

This method is called once when the State object is created. It adds a few people to the list after the first frame has been displayed.

Step 10: Implement AnimatedList

Dart
AnimatedList(
    key: _listKey, // Key for controlling the list
    initialItemCount: 0, // Start with empty list
    itemBuilder: (context, index, animation) {
        return SizeTransition(
            key: UniqueKey(), // Unique key for each item
            sizeFactor: animation, // Animation for list item entry
            child: Card(
                margin: const EdgeInsets.all(8.0), // Card margin
                child: ListTile(
                        tileColor: Colors.grey[200], // Background color
                        shape: RoundedRectangleBorder(
                            borderRadius: BorderRadius.circular(10), // Rounded edges
                        ),
                        title: Text(
                            people[index].name, // Display name
                            style: const TextStyle(
                                fontSize: 20,
                                fontWeight: FontWeight.bold,
                                color: Colors.green,
                            ),
                        ),
                        subtitle: Text(
                            people[index].designation, // Display designation
                            style: const TextStyle(
                                fontSize: 15,
                                fontWeight: FontWeight.bold,
                                color: Colors.grey,
                            ),
                        ),
                        trailing: IconButton(
                        style: ButtonStyle(
                            backgroundColor: WidgetStateProperty.all<Color>(Colors.black12),
                            shape: WidgetStateProperty.all<RoundedRectangleBorder>(
                                RoundedRectangleBorder(
                                    borderRadius: BorderRadius.circular(10),
                                ),
                            ),
                        ),
                        icon: const Icon(Icons.delete, color: Colors.red), // Delete icon
                        onPressed: () {
                            _removePerson(index); // Trigger remove
                        },
                    ),
                ),
            ),
        );
    },
),

We are creating AnimatedList. The AnimatedList uses a GlobalKey to maintain state and animate items when they are inserted or removed. The itemBuilder function creates each item in the list, which is a Card containing a ListTile with person's details. The ListTile also includes a delete IconButton that removes the person from the list when pressed. The SizeTransition widget is used to animate the size of the items during insertion and removal.

Step 11: Add FloatingActionButton

Dart
floatingActionButton: FloatingActionButton(
    backgroundColor: Colors.green, // FAB color
    foregroundColor: Colors.white,
    onPressed: () {
      _showDialog(); // Show dialog on FAB press
    },
    child: const Icon(Icons.add), // FAB icon
),
      
// pop up dialog for adding new person   
TextEditingController nameController = TextEditingController();
TextEditingController designationController = TextEditingController();
// Function to show the add-person dialog
_showDialog() {
 showDialog(
  context: context,
  builder: (BuildContext context) {
    return AlertDialog(
      title: Text('Add Person'), // Dialog title
      content: Column(
        children: <Widget>[
          // Input for Name
          TextField(
            controller: nameController,
            decoration: InputDecoration(
              border: OutlineInputBorder(),
              hintText: "Enter Name",
            ),
          ),
          SizedBox(height: 10),
          // Input for Designation
          TextField(
            controller: designationController,
            decoration: InputDecoration(
              border: OutlineInputBorder(),
              hintText: "Enter Designation",
            ),
          ),
        ],
      ),
      actionsAlignment: MainAxisAlignment.spaceBetween, // Align buttons apart
      actions: <Widget>[
        // Cancel Button
        ElevatedButton(
          style: ElevatedButton.styleFrom(
            backgroundColor: Colors.grey,
            foregroundColor: Colors.white,
          ),
          onPressed: () {
            Navigator.of(context).pop(); // Close dialog
          },
          child: Text('Cancel'),
        ),
        // Add Button
        ElevatedButton(
          style: ElevatedButton.styleFrom(
            backgroundColor: Colors.green,
            foregroundColor: Colors.white,
          ),
          onPressed: () {
            _addPerson(nameController.text, designationController.text); // Add person
            nameController.clear(); // Clear text field
            designationController.clear();
            Navigator.of(context).pop(); // Close dialog
          },
          child: Text('Add'),
        ),
      ],
    );
  },
 );
}


This button will show a dialog which will take Person name and person designation from the user once user clicked on add button _addPerson() method is called to add new person in the list.


Complete Source Code

main.dart
// main.dart

// Importing the Flutter Material package for UI components
import 'package:flutter/material.dart';
// Importing a custom model class for Person data structure
import 'package:flutter_geeks/models/Person.dart';

// Entry point of the Flutter application
void main() {
  runApp(const MyApp()); // Runs the app starting from MyApp widget
}

// Root widget of the application, which doesn't hold state
class MyApp extends StatelessWidget {
  const MyApp({super.key}); // Constructor with optional key

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Geeks', // App title
      theme: ThemeData(primarySwatch: Colors.green), // Global theme
      home: const MainListScreen(), // Main screen widget
      debugShowCheckedModeBanner: false, // Removes debug banner
    );
  }
}

// Main screen widget with mutable state
class MainListScreen extends StatefulWidget {
  const MainListScreen({super.key}); // Constructor

  @override
  State<MainListScreen> createState() => _MainListScreenState(); // Creates state
}

// State class for MainListScreen
class _MainListScreenState extends State<MainListScreen> {
  // Key to uniquely identify and control the AnimatedList
  final GlobalKey<AnimatedListState> _listKey = GlobalKey<AnimatedListState>();

  // List to hold Person objects
  List<Person> people = [];

  // Controllers for name and designation input fields
  TextEditingController nameController = TextEditingController();
  TextEditingController designationController = TextEditingController();

  // Function to add a new Person to the list
  void _addPerson(personName, personDesignation) {
    people.add(Person(personName, personDesignation)); // Add to list
    _listKey.currentState!.insertItem(
      people.length - 1, // Insert at end
      duration: const Duration(milliseconds: 1000), // Animation duration
    );
  }

  // Function to remove a Person from the list by index
  void _removePerson(int index) {
    _listKey.currentState!.removeItem(
      index, // Remove from list at index
      (context, animation) => SizeTransition(
        sizeFactor: animation, // Animate shrinking
        child: const Card(
          margin: EdgeInsets.all(10),
          color: Colors.red,
          child: ListTile(
            title: Text(
              "Deleted",
              style: TextStyle(
                fontSize: 20,
                fontWeight: FontWeight.bold,
                color: Colors.white,
              ),
            ),
          ),
        ),
      ),
      duration: const Duration(milliseconds: 500), // Removal animation
    );
    people.removeAt(index); // Remove from data list
  }

  // Called when the widget is inserted into the widget tree
  @override
  void initState() {
    WidgetsBinding.instance.addPostFrameCallback((_) {
      // Pre-populating the list with dummy people
      _addPerson('Ram', 'Web Developer');
      _addPerson('Abhi', 'Software Engineer');
      _addPerson('Anu', 'Software Engineer');
      _addPerson('Sita', 'Data Scientist');
      _addPerson('Raj', 'DevOps Engineer');
    });
    super.initState();
  }

  // Building the UI
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('GeeksForGeeks'), // AppBar title
        backgroundColor: Colors.green, // AppBar background
        foregroundColor: Colors.white, // AppBar text/icon color
      ),
      body: AnimatedList(
        key: _listKey, // Key for controlling the list
        initialItemCount: 0, // Start with empty list
        itemBuilder: (context, index, animation) {
          return SizeTransition(
            key: UniqueKey(), // Unique key for each item
            sizeFactor: animation, // Animation for list item entry
            child: Card(
              margin: const EdgeInsets.all(8.0), // Card margin
              child: ListTile(
                tileColor: Colors.grey[200], // Background color
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(10), // Rounded edges
                ),
                title: Text(
                  people[index].name, // Display name
                  style: const TextStyle(
                    fontSize: 20,
                    fontWeight: FontWeight.bold,
                    color: Colors.green,
                  ),
                ),
                subtitle: Text(
                  people[index].designation, // Display designation
                  style: const TextStyle(
                    fontSize: 15,
                    fontWeight: FontWeight.bold,
                    color: Colors.grey,
                  ),
                ),
                trailing: IconButton(
                  style: ButtonStyle(
                    backgroundColor: WidgetStateProperty.all<Color>(
                      Colors.black12,
                    ),
                    shape: WidgetStateProperty.all<RoundedRectangleBorder>(
                      RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(10),
                      ),
                    ),
                  ),
                  icon: const Icon(
                    Icons.delete,
                    color: Colors.red,
                  ), // Delete icon
                  onPressed: () {
                    _removePerson(index); // Trigger remove
                  },
                ),
              ),
            ),
          );
        },
      ),
      floatingActionButton: FloatingActionButton(
        backgroundColor: Colors.green, // FAB color
        foregroundColor: Colors.white,
        onPressed: () {
          _showDialog(); // Show dialog on FAB press
        },
        child: const Icon(Icons.add), // FAB icon
      ),
    );
  }

  // Function to show the add-person dialog
  _showDialog() {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text('Add Person'), // Dialog title
          content: Column(
            children: <Widget>[
              // Input for Name
              TextField(
                controller: nameController,
                decoration: InputDecoration(
                  border: OutlineInputBorder(),
                  hintText: "Enter Name",
                ),
              ),
              SizedBox(height: 10),
              // Input for Designation
              TextField(
                controller: designationController,
                decoration: InputDecoration(
                  border: OutlineInputBorder(),
                  hintText: "Enter Designation",
                ),
              ),
            ],
          ),
          actionsAlignment:
              MainAxisAlignment.spaceBetween, // Align buttons apart
          actions: <Widget>[
            // Cancel Button
            ElevatedButton(
              style: ElevatedButton.styleFrom(
                backgroundColor: Colors.grey,
                foregroundColor: Colors.white,
              ),
              onPressed: () {
                Navigator.of(context).pop(); // Close dialog
              },
              child: Text('Cancel'),
            ),
            // Add Button
            ElevatedButton(
              style: ElevatedButton.styleFrom(
                backgroundColor: Colors.green,
                foregroundColor: Colors.white,
              ),
              onPressed: () {
                _addPerson(
                  nameController.text,
                  designationController.text,
                ); // Add person
                nameController.clear(); // Clear text field
                designationController.clear();
                Navigator.of(context).pop(); // Close dialog
              },
              child: Text('Add'),
            ),
          ],
        );
      },
    );
  }
}
models/Person.dart
// models/Person.dart

class Person {
  final String name;
  final String designation;

  Person(this.name, this.designation);
}

Output:

Conclusion

In this article we have created a simple app which displays list of persons having the name and designation using AnimatedList , we have used SizedTransition animation. We have also looked at the constructor and properties of AnimatedList in flutter.


Next Article
Article Tags :

Similar Reads