Search code examples
flutterlistviewdartflutter-animationflutter-animatedlist

How to update data in an AnimatedList in Flutter


How do you update data (add, remove rows) in an AnimatedList in Flutter? I can do it in a ListView by just updating the backing data and calling setState. For example,

setState(() {
  _data.insert(2, 'pig');
});

It seems more complicated in an AnimatedList, though.


Solution

  • The various ways to update the AnimatedList are demonstrated below. The process includes two main steps every time:

    1. Update the data set
    2. Notify the AnimatedList's global key about the change

    Insert single item

    Add "Pig" at index 2.

    enter image description here

    String item = "Pig";
    int insertIndex = 2;
    _data.insert(insertIndex, item);
    _listKey.currentState.insertItem(insertIndex);
    

    Insert multiple items

    Insert three animals at index 2.

    enter image description here

    final items = ['Pig', 'Chichen', 'Dog'];
    int insertIndex = 2;
    _data.insertAll(insertIndex, items);
    // This is a bit of a hack because currentState doesn't have
    // an insertAll() method.
    for (int offset = 0; offset < items.length; offset++) {
      _listKey.currentState.insertItem(insertIndex + offset);
    }
    

    Remove single item

    Remove "Pig" from the list.

    enter image description here

    int removeIndex = 2;
    String removedItem = _data.removeAt(removeIndex);
    // This builder is just so that the animation has something
    // to work with before it disappears from view since the original
    // has already been deleted.
    AnimatedListRemovedItemBuilder builder = (context, animation) {
      // A method to build the Card widget.
      return _buildItem(removedItem, animation);
    };
    _listKey.currentState.removeItem(removeIndex, builder);
    

    Remove multiple items

    Remove "Camel" and "Sheep" from the list.

    enter image description here

    int removeIndex = 2;
    int count = 2;
    for (int i = 0; i < count; i++) {
      String removedItem = _data.removeAt(removeIndex);
      AnimatedListRemovedItemBuilder builder = (context, animation) {
        return _buildItem(removedItem, animation);
      };
      _listKey.currentState.removeItem(removeIndex, builder);
    }
    

    Supplemental code

    main.dart

    import 'package:flutter/material.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          debugShowCheckedModeBanner: false,
          home: Scaffold(
            appBar: AppBar(title: Text('Update AnimatedList data')),
            body: BodyWidget(),
          ),
        );
      }
    }
    
    class BodyWidget extends StatefulWidget {
      @override
      BodyWidgetState createState() {
        return new BodyWidgetState();
      }
    }
    
    class BodyWidgetState extends State<BodyWidget> {
    
      // the GlobalKey is needed to animate the list
      final GlobalKey<AnimatedListState> _listKey = GlobalKey();
    
      // backing data
      List<String> _data = ['Horse', 'Cow', 'Camel', 'Sheep', 'Goat'];
    
      @override
      Widget build(BuildContext context) {
        return Column(
          children: <Widget>[
            SizedBox(
              height: 400,
              child: AnimatedList(
                key: _listKey,
                initialItemCount: _data.length,
                itemBuilder: (context, index, animation) {
                  return _buildItem(_data[index], animation);
                },
              ),
            ),
            RaisedButton(
              child: Text(
                'Insert single item',
                style: TextStyle(fontSize: 20),
              ),
              onPressed: () {
                _onButtonPress();
              },
            )
          ],
        );
      }
    
      Widget _buildItem(String item, Animation animation) {
        return SizeTransition(
          sizeFactor: animation,
          child: Card(
            child: ListTile(
              title: Text(
                item,
                style: TextStyle(fontSize: 20),
              ),
            ),
          ),
        );
      }
    
      void _onButtonPress() {
        // replace this with method choice below
        _insertSingleItem();
      }
    
      void _insertSingleItem() {
        String item = "Pig";
        int insertIndex = 2;
        _data.insert(insertIndex, item);
        _listKey.currentState.insertItem(insertIndex);
      }
    
      void _insertMultipleItems() {
        final items = ['Pig', 'Chichen', 'Dog'];
        int insertIndex = 2;
        _data.insertAll(insertIndex, items);
        // This is a bit of a hack because currentState doesn't have
        // an insertAll() method.
        for (int offset = 0; offset < items.length; offset++) {
          _listKey.currentState.insertItem(insertIndex + offset);
        }
      }
    
      void _removeSingleItems() {
        int removeIndex = 2;
        String removedItem = _data.removeAt(removeIndex);
        // This builder is just so that the animation has something
        // to work with before it disappears from view since the original
        // has already been deleted.
        AnimatedListRemovedItemBuilder builder = (context, animation) {
          // A method to build the Card widget.
          return _buildItem(removedItem, animation);
        };
        _listKey.currentState.removeItem(removeIndex, builder);
      }
    
      void _removeMultipleItems() {
        int removeIndex = 2;
        int count = 2;
        for (int i = 0; i < count; i++) {
          String removedItem = _data.removeAt(removeIndex);
          AnimatedListRemovedItemBuilder builder = (context, animation) {
            return _buildItem(removedItem, animation);
          };
          _listKey.currentState.removeItem(removeIndex, builder);
        }
      }
    }
    

    Note

    • If your list items include any stateful widgets then you will need to give them keys so that the system can keep track of them.
    • Although I wrote this answer before I wrote the Medium article, I am now maintaining my answer on Medium. Check there for the latest updates.