Almost every app uses dynamic ListView. Items are added, removed and changed all the time. Without animation, this can be confusing. AnimatedList provides an easy way to animate ListView items in Flutter.

Flutter ListView Animation
AnimatedList(
              key: listKey,
              initialItemCount: items.length,
              itemBuilder: (context, index, animation) {
                return buildItem(context, index, animation);
              },
            )
......

Widget buildItem(
      BuildContext context, int index, Animation<double> animation) {
    return SizeTransition(
      key: ValueKey<int>(index),
      axis: Axis.vertical,
      sizeFactor: animation,
      child: SizedBox(
        child: ListTile(
          title: Text('${items[index].name}'),
        ),
      ),
    );
  }

ItemBuilder function will be called for every index for the ListView, so you can construct each item. You also get an animation object, which automatically starts when the item is added and which you can use to animate the item in. Your animation can be anything. Unless your list starts empty, you will also want to provide the initialItemCount.

Trigger an Animation

You need to tell the AnimatedList whenever there is anything added or removed from the underlying data structure. To do this you call methods on the AnimatedListState.

final GlobalKey<AnimatedListState> listKey = GlobalKey<AnimatedListState>();

Attach AnimatedListState to the AnimatedList widget. And now you can call insertItem removeItem from anywhere.

Insert Items Animation

With insertItem, you tell AnimatedList that there is a new item at index and that it should start the animation. To construct the newly added item, AnimatedList uses the itemBuilder, which you already defined.

 _addItem() {
    setState(() {
      listKey.currentState.insertItem(items.length, duration: const Duration(seconds: 1));
      int id = rng.nextInt(5000);
      items.add(new Item(name: "New Item $id"));
    });
  }

It is important that you not only call the AnimatedList state method but also update your data source.

Remove Items Animation

removeItem is similar. You tell AnimatedList that the item at index is being removed. You also need to provide a Builder for the widget to show while it’s animating out.it’s important to remove the item from the underlying data structure.

_removeItem() {
    setState(() {
      int id = rng.nextInt(items.length);
      listKey.currentState.removeItem(
        id,(context, animation) => buildItem(context, 0, animation),
        duration: const Duration(milliseconds: 250),
      );
      items.removeAt(id);
    });
  }

Complete example

import 'package:flutter/material.dart';
import 'dart:math';

void main() => runApp(MyApp());

class Item {
  Item({this.name});
  String name;
}

class MyApp extends StatelessWidget {
  const MyApp({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Dynamic List',
      home: ListScreen(),
    );
  }
}

class ListScreen extends StatefulWidget {
  @override
  _ListScreenState createState() => _ListScreenState();
}

class _ListScreenState extends State<ListScreen> {
  List<Item> items = new List();
  final GlobalKey<AnimatedListState> listKey = GlobalKey<AnimatedListState>();
  var rng = new Random();

  _addItem() {
    setState(() {
      listKey.currentState.insertItem(items.length, duration: const Duration(seconds: 1));
      int id = rng.nextInt(5000);
      items.add(new Item(name: "New Item $id"));
    });
  }
  _removeItem() {
    setState(() {
      int id = rng.nextInt(items.length);
      listKey.currentState.removeItem(
        id,(context, animation) => buildItem(context, 0, animation),
        duration: const Duration(milliseconds: 250),
      );
      items.removeAt(id);
    });
  }

  Widget buildItem(
      BuildContext context, int index, Animation<double> animation) {
    return SizeTransition(
      key: ValueKey<int>(index),
      axis: Axis.vertical,
      sizeFactor: animation,
      child: SizedBox(
        child: ListTile(
          title: Text('${items[index].name}'),
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    final Map<int, Animation<double>> animations = <int, Animation<double>>{};
    return Scaffold(
        appBar: AppBar(
          title: Text("Dynamic List"),
          actions: <Widget>[
            IconButton(
              icon: const Icon(Icons.add),
              onPressed: _addItem,
            ),
            IconButton(
              icon: const Icon(Icons.remove),
              onPressed: _removeItem,
            )
          ],
        ),
        body: Directionality(
            textDirection: TextDirection.ltr,
            child: AnimatedList(
              key: listKey,
              initialItemCount: items.length,
              itemBuilder: (context, index, animation) {
                return buildItem(context, index, animation);
              },
            )
        )
    );
  }
}