Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to animate the items rendered initially using Animated List in flutter

I am using Animated List in flutter to load a list class, while adding or removing the items, the animation works but when the list is initially loaded, the animation does not work. Is there a way to animate items when initially loading the list.

class AnimationTest extends StatefulWidget {
  @override
  _AnimationTestState createState() => _AnimationTestState();
}

class _AnimationTestState extends State<AnimationTest> with SingleTickerProviderStateMixin {
  AnimationController _controller;

  @override
  void initState() {
    _controller = AnimationController(
      vsync: this,
      duration: const Duration(seconds: 1),
    );
    super.initState();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedList(
      key: _listKey,
      initialItemCount: 3,
      itemBuilder: (BuildContext context, int index, Animation animation) {
        return SlideTransition(
          position: animation.drive(Tween<Offset>(begin: Offset(1.0, 0.0), end: Offset.zero)
              .chain(CurveTween(curve: Curves.decelerate))),
          child: Row(
            children: <Widget>[
              Expanded(
                child: InkWell(
                  onTap: () => _listKey.currentState.insertItem(0,duration: Duration(milliseconds: 600)),
                  child: Container(
                      padding: EdgeInsets.only(left: 10, right: 10),
                      height: 100,
                      child: Card(
                        margin: EdgeInsets.symmetric(vertical: 4.0),
                        color: Theme.of(context).backgroundColor,
                      )),
                ),
              ),
            ],
          ),
        );
      },
    );
  }
}
like image 569
Shashi Kiran Avatar asked Jul 18 '19 17:07

Shashi Kiran


People also ask

How do you make a custom animation on Flutter?

Initializing AnimationController After that, we are initializing controller in initState to animate when the view is ready. We set the duration as 1 second. forward() method provides to start the animation until the end, and addListener() calls the listener every time the value changes.


1 Answers

Because AnimatedList can only animate when adding/removing item in the list. You need to add each item individually by using insertItem or removeItem from AnimatedListState. One way to achieve a nice loading effect is to delay each time you insert/remove item.

demo load/unload list items

Here is the code to chain Future so that each item is loaded one after another after a specified delay

var future = Future(() {});
for (var i = 0; i < fetchedList.length; i++) {
  future = future.then((_) {
    return Future.delayed(Duration(milliseconds: 100), () {
      // add/remove item
    });
  });
}

From there you can create a loadItems() method to initialize all items in the AnimatedList in initState(). Remember to update both the underlying data structure (_listItems) and AnimatedList itself for it to work.

var _listItems = <Widget>[];
final GlobalKey<AnimatedListState> _listKey = GlobalKey();

@override
void initState() {
  super.initState();

  _loadItems();
}

void _loadItems() {
  // fetching data from web api, local db...
  final fetchedList = [
    ListTile(
      title: Text('Economy'),
      trailing: Icon(Icons.directions_car),
    ),
    ListTile(
      title: Text('Comfort'),
      trailing: Icon(Icons.motorcycle),
    ),
    ListTile(
      title: Text('Business'),
      trailing: Icon(Icons.flight),
    ),
  ];

  var future = Future(() {});
  for (var i = 0; i < fetchedList.length; i++) {
    future = future.then((_) {
      return Future.delayed(Duration(milliseconds: 100), () {
        _listItems.add(fetchedList[i]);
        _listKey.currentState.insertItem(i);
      });
    });
  }
}

This is the complete example. I added 2 buttons in the app bar so you can play around with the animations

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'YourAwesomeApp',
      home: PageWithAnimatedList(),
    );
  }
}

class PageWithAnimatedList extends StatefulWidget {
  @override
  _PageWithAnimatedListState createState() => _PageWithAnimatedListState();
}

class _PageWithAnimatedListState extends State<PageWithAnimatedList> {
  var _listItems = <Widget>[];
  final GlobalKey<AnimatedListState> _listKey = GlobalKey();

  @override
  void initState() {
    super.initState();

    _loadItems();
  }

  void _loadItems() {
    // fetching data from web api, db...
    final fetchedList = [
      ListTile(
        title: Text('Economy'),
        trailing: Icon(Icons.directions_car),
      ),
      ListTile(
        title: Text('Comfort'),
        trailing: Icon(Icons.motorcycle),
      ),
      ListTile(
        title: Text('Business'),
        trailing: Icon(Icons.flight),
      ),
    ];

    var future = Future(() {});
    for (var i = 0; i < fetchedList.length; i++) {
      future = future.then((_) {
        return Future.delayed(Duration(milliseconds: 100), () {
          _listItems.add(fetchedList[i]);
          _listKey.currentState.insertItem(_listItems.length - 1);
        });
      });
    }
  }

  void _unloadItems() {
    var future = Future(() {});
    for (var i = _listItems.length - 1; i >= 0; i--) {
      future = future.then((_) {
        return Future.delayed(Duration(milliseconds: 100), () {
          final deletedItem = _listItems.removeAt(i);
          _listKey.currentState.removeItem(i,
              (BuildContext context, Animation<double> animation) {
            return SlideTransition(
              position: CurvedAnimation(
                curve: Curves.easeOut,
                parent: animation,
              ).drive((Tween<Offset>(
                begin: Offset(1, 0),
                end: Offset(0, 0),
              ))),
              child: deletedItem,
            );
          });
        });
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        actions: <Widget>[
          IconButton(icon: Icon(Icons.add), onPressed: _loadItems),
          IconButton(icon: Icon(Icons.remove), onPressed: _unloadItems)
        ],
      ),
      body: AnimatedList(
        key: _listKey,
        padding: EdgeInsets.only(top: 10),
        initialItemCount: _listItems.length,
        itemBuilder: (context, index, animation) {
          return SlideTransition(
            position: CurvedAnimation(
              curve: Curves.easeOut,
              parent: animation,
            ).drive((Tween<Offset>(
              begin: Offset(1, 0),
              end: Offset(0, 0),
            ))),
            child: _listItems[index],
          );
        },
      ),
    );
  }
}

Live Demo

like image 105
NearHuscarl Avatar answered Oct 23 '22 12:10

NearHuscarl