Programmatically scrolling to the end of a ListView

yyoon picture yyoon · Apr 19, 2017 · Viewed 69.6k times · Source

I have a scrollable ListView where the number of items can change dynamically. Whenever a new item is added to the end of the list, I would like to programmatically scroll the ListView to the end. (e.g., something like a chat message list where new messages can be added at the end)

My guess is that I would need to create a ScrollController in my State object and pass it manually to the ListView constructor, so I can later call animateTo() / jumpTo() method on the controller. However, since I cannot easily determine the maximum scroll offset, it seems impossible to simply perform a scrollToEnd() type of operation (whereas I can easily pass 0.0 to make it scroll to the initial position).

Is there an easy way to achieve this?

Using reverse: true is not a perfect solution for me, because I would like the items to be aligned at the top when there are only a small number of items that fit within the ListView viewport.

Answer

CopsOnRoad picture CopsOnRoad · Oct 29, 2018

Use ScrollController.jumpTo() or ScrollController.animateTo() method to achieve this.

Example:

final _controller = ScrollController();

@override
Widget build(BuildContext context) {
  
  // After 1 second, it takes you to the bottom of the ListView
  Timer(
    Duration(seconds: 1),
    () => _controller.jumpTo(_controller.position.maxScrollExtent),
  );

  return ListView.builder(
    controller: _controller,
    itemCount: 50,
    itemBuilder: (_, __) => ListTile(title: Text('ListTile')),
  );
}

If you want smooth scrolling, then instead of using jumpTo above use

_controller.animateTo(
  _controller.position.maxScrollExtent,
  duration: Duration(seconds: 1),
  curve: Curves.fastOutSlowIn,
);