gatti
gatti

Reputation: 1133

Flutter: animate item removal in ListView

I am building a ListView from a Stream. I need to animate deletions and insertions to that list, but have no idea how.

I have seen this sample by Flutter but it is not related to streams in any way: https://flutter.io/catalog/samples/animated-list/

Any help greatly appreciated :)

new StreamBuilder(

    stream: feed.stream, // this is a Stream<List<Product>>

    builder: (context, snapshot) {
      if (!snapshot.hasData)
        return const Text('Loading products');
      return new ListView.builder(
          itemCount: snapshot.data.length,
          itemBuilder: (context, index) {
            Product product = snapshot.data[index];
            return new ProductWidget(product);
          });
    });

Upvotes: 18

Views: 21800

Answers (3)

Nils Tierecke
Nils Tierecke

Reputation: 444

I would create AnimatedSwitcher items and add them to the list. Here is a function that accept a child (which you want to add to the list) and adds animation to it.

// Makes a fade transition for the widget
AnimatedSwitcher fadeTransition(Widget child) {
return AnimatedSwitcher(
  duration: const Duration(milliseconds: 500),
  child: child,
  transitionBuilder: (child, animation) {
    return FadeTransition(
      opacity: animation,
      child: child,
    );
  },
);

}

Upvotes: 0

Tharun kumar
Tharun kumar

Reputation: 1

Even I wanted to do the same, i am building a todo app, in that from firebase I load all the documents in a list using stream builder.But couldn't animate the insertion and deletion of items.So I had to use a separate list to store the data from the stream builder to that list, then perform animation on insertion and deletion to that list using the insert and remove item methods from the animated list. This is the only way possible. Correct me if I'm wrong

Upvotes: 0

Suragch
Suragch

Reputation: 511736

As an alternative to ListView, you can use an AnimatedList:

enter image description here

// Remove "Pig" from the list
int removeIndex = 2;

// remove the item from the data list backing the AnimatedList
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);
};

// notify the AnimatedList that the item was removed
_listKey.currentState.removeItem(removeIndex, builder);

This article explains more. Here is the full code:

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);
    }
  }

  void _removeAllItems() {
    final length = _data.length;
    for (int i = length - 1; i >= 0; i--) {
      String removedItem = _data.removeAt(i);
      AnimatedListRemovedItemBuilder builder = (context, animation) {
        return _buildItem(removedItem, animation);
      };
      _listKey.currentState.removeItem(i, builder);
    }
  }

  void _updateSingleItem() {
    final newValue = 'I like sheep';
    final index = 3;
    setState(() {
      _data[index] = newValue;
    });
  }
}

Upvotes: 6

Related Questions