This post describes a very similar problem, but the answer there doesn\'t solve all problems:
I have a potentially long List, where the user can add new items (on at
I combined scroll to maxScrollExtent
with Scrollable.ensureVisible
and each of them fixed the flaws of the other.
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
class MyList extends StatefulWidget {
MyList({Key key}) : super(key: key);
@override
_MyListState createState() => _MyListState();
}
class _MyListState extends State<MyList> {
final ScrollController _scrollController = ScrollController();
final lastKey = GlobalKey();
List<String> items;
@override
void initState() {
super.initState();
items = List<String>.generate(8, (i) => "Item $i");
}
void add() {
setState(() {
items.add("new Item ${items.length}");
});
SchedulerBinding.instance.addPostFrameCallback((_) => scrollToEnd());
}
void scrollToEnd() async {
await _scrollController.animateTo(
_scrollController.position.maxScrollExtent,
duration: const Duration(milliseconds: 350),
curve: Curves.easeOut);
Scrollable.ensureVisible(lastKey.currentContext);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "List",
home: Scaffold(
body: ListView.builder(
controller: _scrollController,
itemCount: items.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return ListTile(
title: Text('${items[index]}'),
key: index == items.length - 1 ? lastKey : null,
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () {
add();
},
child: Icon(Icons.add),
),
));
}
}
Scrollable.ensureVisible
itself cannot provide visibility if the item has not yet been created, but copes with them when item is very close.
Specifying a too large scrollPosition works without errors, the ScrollController then automatically scrolls to the final maximum value. I define a _scrollController and execute the following command:
_scrollController.animateTo(
_scrollController.position.maxScrollExtent + 200,
duration: const Duration(milliseconds: 350),
curve: Curves.easeOut);
or
_scrollController.jumpTo(_scrollController.position.maxScrollExtent + 200);