I have a ListView of customers where the user is able to check/uncheck each customer to mark them as a 'favourite'. However, each time a ListItem is tapped, the ListView jumps back to the top of the screen.
How do I prevent this from happening? I only want the Checkbox to refresh, not the entire screen, and to prevent the screen from jumping to the top each time.
@override
Widget build(BuildContext context) {
customers = getAllCustomers();
return Scaffold(
appBar: _getAppBar(),
body: customers != null
? FutureBuilder(
future: getFavouriteCustomers(), // contains IDs of favourite customers
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasData) {
List<String> favouriteCustomersList = snapshot.data;
return ListView.builder(
itemCount: customers?.length ?? 0,
itemBuilder: (BuildContext context, int index) {
customer c = customers?.elementAt(index);
if (favouriteCustomersList.contains(c.id)) {
c.isSelected = true;
}
return ListTile(
title: Text(c.name),
trailing: Checkbox(
value: c.isFavourite,
onChanged: (newValue) {}),
onTap: () {
if (c.isSelected) {
setState(() {
c.setFavourite(false);
});
} else {
setState(() {
c.setFavourite(true);
}
}
},
);
});
}
} else {
return CircularProgressIndicator();
}
})
: Center(
child: CircularProgressIndicator(),
);
);
}
This answer suggests using a custom ScrollController with keepScrollOffset set to true , however this is the default value and setting it explicitly to true therefore does not change anything.
We can use ListView. builder(..) in Stateless Widgets if we want to display dynamic (different) contents every time the widget is loaded within an application. With Stateful widgets, it can change the contents of the screen dynamically.
All you have to do is set Global Keys for your widgets and call Scrollable. ensureVisible on the key of your widget you want to scroll to. For this to work your ListView should be a finite List of objects.
By using ListView, only the items that are visible are mounted and painted. On the other hand, by using SingleChildScrollView+Column, the entire item list is mounted+painted, even if only a few items are visible.
Ensure you are doing this in a StatefulWidget.
Create a ScrollController
as field in the state class (not the widget class):
_controller = ScrollController(keepScrollOffset: true);
This way the controller will be preserved in the state and not recreated on rebuilds.
controller: _controller,
@override
void dispose() {
_controller.dispose();
super.dispose();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With