how to keep the state of my widgets after scrolling?
ListView.builder & GridView.builder makes items on demand. That means ,they construct item widgets & destroy them when they going beyond more than cacheExtent
.
So you cannot keep any ephemeral state inside that item widgets.(So most of time item widgets are Stateless, but when you need to use keepAlive
you use Stateful item widgets.
In this case you have to keep your state in a parent widget.So i think the best option you can use is State management approach for this. (like provider package, or scoped model).
Below link has similar Example i see in flutter.dev
Link for Example
Hope this answer will help for you
You have to store the state (favorite or not) in a parent widget. The ListView.builder
widget creates and destroys items on demand, and the state is discarded when the item is destroyed. That means the list items should always be stateless widgets.
Here is an example with interactivity:
class Item {
Item({this.name, this.isFavorite});
String name;
bool isFavorite;
}
class MyList extends StatefulWidget {
@override
State<StatefulWidget> createState() => MyListState();
}
class MyListState extends State<MyList> {
List<Item> items;
@override
void initState() {
super.initState();
// Generate example items
items = List<Item>();
for (int i = 0; i < 100; i++) {
items.add(Item(
name: 'Item $i',
isFavorite: false,
));
}
}
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ListItem(
items[index],
() => onFavoritePressed(index),
);
},
);
}
onFavoritePressed(int index) {
final item = items[index];
setState(() {
item.isFavorite = !item.isFavorite;
});
}
}
class ListItem extends StatelessWidget {
ListItem(this.item, this.onFavoritePressed);
final Item item;
final VoidCallback onFavoritePressed;
@override
Widget build(BuildContext context) {
return ListTile(
title: Text(item.name),
leading: IconButton(
icon: Icon(item.isFavorite ? Icons.favorite : Icons.favorite_border),
onPressed: onFavoritePressed,
),
);
}
}
Other answer are better for your case but this an alternative and can be used if you want to only keep several elements alive during a scroll. In this case you can use AutomaticKeepAliveClientMixin with keepAlive.
class Foo extends StatefulWidget {
@override
FooState createState() {
return new FooState();
}
}
class FooState extends State<Foo> with AutomaticKeepAliveClientMixin {
bool shouldBeKeptAlive = false;
@override
Widget build(BuildContext context) {
super.build(context);
shouldBeKeptAlive = someCondition();
return Container(
);
}
@override
bool get wantKeepAlive => shouldBeKeptAlive;
}
If you don't have many items in the ListView
you can replace it with a SingleChildScrollview
and a Column
so that the Widgets aren't recycled. But it sounds like you should have a list of items where each item has an isFavourite
property, and control the icon based on that property. Don't forget to setState
when toggling the favorite.