Reputation: 1133
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
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
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
Reputation: 511736
As an alternative to ListView
, you can use an AnimatedList
:
// 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