Flutter ListView scroll to bottom on build [duplicate]
Asked Answered
S

3

8

Is it possible to make a Flutter listview scroll to the bottom after it initially loads all its data? I am aware of the scrollController.jumpTo() logic, however this has to be called within some event handler, how would you invoke this upon the completion of a listview building so as soon as the screen opens it scrolls to the bottom?

Schnauzer answered 4/4, 2020 at 20:48 Comment(1)
Did u find a way to solve this problem??Zymogen
D
21

Well, I think you are in the correct track to achieve it!

You should try _controller.jumpTo() and fire that event programatically.

You can create a Timer, and call the _controller in there, after 500 milliseconds (half of a second).

ScrollController _myController = ScrollController();

@override
Widget build(BuildContext context) {
      
      // here we set the timer to call the event
      Timer(Duration(milliseconds: 500), () => _myController.jumpTo(_myController.position.maxScrollExtent));

      // add _myController to the ListView
      return ListView.builder(
         controller: _myController,
         // itemCount: yourItemsCount,
         // ...
      )
}

Please check this answer also --> Programmatically scrolling to the end of a ListView

And also this one --> How to get full size of a ScrollController

There they use SchedulerBinding.instance.addPostFrameCallback which I think is also a good solution to fire your scroll.

SchedulerBinding.instance.addPostFrameCallback((_) {
            _myController.animateTo(
              _myController.position.maxScrollExtent,
              duration: const Duration(milliseconds: 500),
              curve: Curves.easeOut,
            );
          });

UPDATE:

Please try this code, no transition, no visible jump to me.

Is a combination of my previous paragraphs.

Just beware, if the number of lines grow, like 10000.

But I think you should control the number of messages displayed.

  Widget build(BuildContext context) {
    final items = List<String>.generate(50, (i) => "Item $i");

    ScrollController _controller = ScrollController();

    SchedulerBinding.instance.addPostFrameCallback((_) {
        _controller.jumpTo(_controller.position.maxScrollExtent);
      });

    return Scaffold(
        body: SafeArea(
          child: ListView.builder(
            controller: _controller,
            itemCount: items.length,
            itemBuilder: (context, index) {
              return ListTile(
                title: Text('${items[index]}'),
              );
            },
          ),
        ));
  }
Discernible answered 4/4, 2020 at 23:19 Comment(4)
Thanks for your response encubos however, no matter how much I reduce the Duration, you still see a visible transition from the top of the conversation to the bottom upon the screen opening. I essentially want the screen to open at the bottom of the ListView as is the case with all chat apps (like WhatsApp etc) since the latest conversation is at the bottom.Schnauzer
I updated my answer, with a new code at the bottom. Its a complete build function with 50 rows displayed. Try it.Discernible
Do not add SchedulerBinding... nor WidgetBinding... to your build() method (there are few scenarios that warrant this). Doing so results in the 'ListViev' scrolling to the bottom on every setState() call / build() update call. e.g. Using a bloc to a firestore stream, any document change will cause the UI to scroll to the bottom.Denyse
Think I found the reason for the animated bounce - it doesn't have to do with jumpTo exactly, but rather jumping too far. As per the docs - Immediately after the jump, a ballistic activity is started, in case the value was out of range.Geese
S
2

I have figured out a way to reliably scroll to the bottom without major headaches in other answers. The only downside is it only looks good with Curves.linear.

    Future.doWhile(() {
      if (scrollController.position.extentAfter == 0)
        return Future.value(false);
      return scrollController
          .animateTo(scrollController.position.maxScrollExtent,
              duration: Duration(milliseconds: 100), curve: Curves.linear)
          .then((value) => true);
    });
Shiism answered 20/10, 2022 at 4:38 Comment(0)
P
0

I think the main problems why ListView.builder cannot show all of items to the bottom depends on whether you put the downloaded data from Database (Firestore) inside a class or not. In my case, it did. So I transferred all downloaded data (QuerySnapshot) into another class or GetX controller and loaded all of them from that data.

Packer answered 10/9, 2022 at 1:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.