Flutter AnimatedList – Tutorial and Examples

Last updated on January 12, 2021 A Goodman Loading... Post a comment

AnimatedList is a built-in widget in Flutter, used to implement a list view that animates its items when they are inserted or removed. This helps the user feel less sudden and more pleasant about the change of the list.

In this article, you will learn how to use AnimatedList through two complete examples. The first one is simple and the second one is a little bit more complicated.

Example 1: Basic

This example helps you learn the fundamental of AnimatedList.

Preview:

For simplicity’s sake, the sample app only contains a list and a floating button (we’ll do advanced things in the second example).

What’s the point?

  • When the user presses the button, a new item will be added to the list. We use the [_listKey].currentState.insertItem() method to initialize the animation.
  • When the user touches an item, it will be removed. We use the [_listKey].currentState.removeItem() method to trigger the animation.

The full code (main.dart):

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

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Kindacode.com',
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  // Items in the list
  final _items = [];

  // The key of the list
  final GlobalKey<AnimatedListState> _key = GlobalKey();

  // Add a new item to the list
  // This is trigger when the floating button is pressed
  void _addItem() {
    _items.insert(0, "Item ${_items.length + 1}");
    _key.currentState.insertItem(0, duration: Duration(seconds: 1));
  }

  // Remove an item
  // This is trigger when the trash icon associated with an item is tapped
  void _removeItem(int index) {
    _key.currentState.removeItem(index, (_, animation) {
      return SizeTransition(
        sizeFactor: animation,
        child: Card(
          margin: EdgeInsets.all(10),
          elevation: 10,
          color: Colors.purple,
          child: ListTile(
            contentPadding: EdgeInsets.all(15),
            title: Text("Goodbye", style: TextStyle(fontSize: 24)),
          ),
        ),
      );
      ;
    }, duration: Duration(seconds: 1));

    _items.removeAt(index);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Kindacode.com'),
      ),
      body: AnimatedList(
        key: _key,
        initialItemCount: 0,
        padding: EdgeInsets.all(10),
        itemBuilder: (_, index, animation) {
          return SizeTransition(
            sizeFactor: animation,
            child: Card(
              margin: EdgeInsets.all(10),
              elevation: 10,
              color: Colors.orange,
              child: ListTile(
                contentPadding: EdgeInsets.all(15),
                title: Text(_items[index], style: TextStyle(fontSize: 24)),
                trailing: IconButton(
                  icon: Icon(Icons.delete),
                  onPressed: () => _removeItem(index),
                ),
              ),
            ),
          );
        },
      ),
      floatingActionButton:
          FloatingActionButton(onPressed: _addItem, child: Icon(Icons.add)),
    );
  }
}

Example 2

This one is similar to the example above but there some difference:

  • Key is no longer used to remove an item. Instead, we use context and the AnimatedList.of(context).removeItem() method.
  • Many animation effects are used in combination.

Preview:

The full code (main.dart):

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

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Kindacode.com',
      theme: ThemeData(
          primaryColor: Colors.green, accentColor: Colors.greenAccent),
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  // Items in the list
  final _items = ["Item 0"];

  // The key of the list
  final GlobalKey<AnimatedListState> _key = GlobalKey();

  // Add a new item to the list
  // This is trigger when the floating button is pressed
  void _addItem() {
    _items.insert(0, "Item ${_items.length + 1}");
    _key.currentState.insertItem(0, duration: Duration(seconds: 1));
  }

  // Remove an item
  // This is trigger when an item is tapped
  void _removeItem(int index, BuildContext context) {
    AnimatedList.of(context).removeItem(index, (_, animation) {
      return FadeTransition(
        opacity: animation,
        child: SizeTransition(
          sizeFactor: animation,
          child: SizedBox(
            height: 150,
            child: Card(
              margin: const EdgeInsets.symmetric(vertical: 20),
              elevation: 10,
              color: Colors.red[400],
              child: Center(
                child: Text("I am going away",
                    style: TextStyle(fontSize: 28)),
              ),
            ),
          ),
        ),
      );
    }, duration: Duration(seconds: 1));

    _items.removeAt(index);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Kindacode.com'),
        actions: [
          IconButton(onPressed: _addItem, icon: Icon(Icons.plus_one_outlined),)
        ],
      ),
      body: AnimatedList(
        key: _key,
        initialItemCount: 1,
        padding: EdgeInsets.all(10),
        itemBuilder: (context, index, animation) {
          return SlideTransition(
            position: Tween<Offset>(
              begin: const Offset(-1, -0.5),
              end: Offset(0, 0),
            ).animate(animation),
            child: RotationTransition(
              turns: animation,
              child: SizeTransition(
                axis: Axis.vertical,
                sizeFactor: animation,
                child: SizedBox(
                  height: 150,
                  child: InkWell(
                    onTap: () => _removeItem(index, context),
                    child: Card(
                      margin: const EdgeInsets.symmetric(vertical: 20),
                      elevation: 10,
                      color: Colors.primaries[
                          (index * 100) % Colors.primaries.length][300],
                      child: Center(
                        child:
                            Text(_items[index], style: TextStyle(fontSize: 28)),
                      ),
                    ),
                  ),
                ),
              ),
            ),
          );
        },
      ),
    );
  }
}

API

Construtor:

AnimatedList({
  Key key, 
  @required AnimatedListItemBuilder itemBuilder, 
  int initialItemCount: 0, 
  Axis scrollDirection: Axis.vertical, 
  bool reverse: false, 
  ScrollController controller, 
  bool primary, 
  ScrollPhysics physics, 
  bool shrinkWrap: false, 
  EdgeInsetsGeometry padding
})

Details about the parameters

The first 4 parameters listed in the table below are used most frequently:

ParameterTypeDescription
itemBuilder (required)AnimatedListItemBuilderBuilds items in the list when they are scrolled into view
initialItemCountintThe number of items at the beginning
controllerScrollControllerControls the scroll position of the list
keyKeyUsed to to access the list from outside
scrollDirectionAxisDetermines the scrolling behaviors of items
reverseboolDetermine whether the scroll view scrolls in the reading direction
physicsScrollPhysicsDecides how the scroll should behave on user input
shrinkWrapboolDetermine whether the size of the list should take full available space or match it to the size of items in the list
paddingEdgeInsetsGeometrySet padding around the list items
primaryboolWhether this is the primary scroll view associated with the parent PrimaryScrollController

Conclusion

We have learned and discovered a lot of things about AnimatedList, helping us to have more options in the implementation of real applications. You can explore other kinds of list widget in Flutter in the following articles: SliverList – Tutorial and Example, Highlight selected items in a ListView, How to implement a horizontal ListView, Scrolling to the desired item in a ListView.

If you would like to discover more interest things, check out our Flutter topic page or Dart topic page for the latest tutorials and examples.

Related Articles

guest
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x