Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter - ListView.builder: Initial scroll position

I want to setup the initial scroll position of a ListView.builder, I want the list to start at the bottom 0.0

If I setup reverse on the listView of course I get the initial scroll position to be the desired one, but what I need is to have the last children on the bottom, is a chat app.

This is the list builder, MessageItem() is the chat message

ListView.builder(
                    shrinkWrap: true,
                    controller: _scrollController,
                    itemCount: snapshot.data.documents.length,
                    padding: EdgeInsets.all(10.0),
                    itemBuilder: (BuildContext context, int index) =>
                        MessageItem(
                            index: index,
                            document: snapshot.data.documents[index],
                            myId: myId));

This is the animation I have when someone send the message


_scrollController.animateTo(
                _scrollController.position.maxScrollExtent,
                duration: const Duration(milliseconds: 500),
                curve: Curves.easeOut);

the animation works okay.


What I want is the list scroll position to be already at the bottom when the user enters the chat room.

like image 534
Irving Armenta Avatar asked Aug 15 '19 01:08

Irving Armenta


People also ask

How do I scroll to a specific position in flutter ListView?

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. If you are using ListView.

How do you scroll a specific element in flutter?

A scroll controller creates a [ScrollPosition] to manage the state-specific to an individual [Scrollable] widget. To use a custom [ScrollPosition], subclass [ScrollController] and override [createScrollPosition]. A [ScrollController] is a [Listenable].

How do you control scrolling in flutter?

If you want to use this controller function, you can add a ScrollNotification and keep calling it over and over again when the scroll ends, until the stop button is pressed.


4 Answers

for avoid error where scroll isnt attached for any list, use, WidgetsBinding to pullout after build is ready.


void _scrollToBottom() {
    if (_scrollController.hasClients) {
      _scrollController.animateTo(_scrollController.position.maxScrollExtent,
          duration: Duration(milliseconds: 300), curve: Curves.elasticOut);
    } else {
      Timer(Duration(milliseconds: 400), () => _scrollToBottom());
    }
 }

@override
Widget build(BuildContext context) {

  WidgetsBinding.instance.addPostFrameCallback((_) => _scrollToBottom());

  {...} //rest of code;
}
like image 69
Rodrigo Avatar answered Oct 19 '22 19:10

Rodrigo


You can set one of ScrollController's property: initialScrollOffset

But on the condition that you know the offset position of the target item/index.

ScrollController _controller = ScrollController(initialScrollOffset: itemHeight * index)

(note that this example assumes that the sizes of your list's widgets are of constant size, but if you don't have constant widget sizes in your list, then you must be able to calculate the final offset position of your target item - and that is a whole other issue)

Or, if you want it to always be the last item/index, then it's much easier:

ScrollController _controller = ScrollController(initialScrollOffset: _controller.position.maxScrollExtent)
like image 44
TWL Avatar answered Oct 19 '22 19:10

TWL


The solution for me was:

SingleChildScrollView(
                reverse: true,
                child: Container(),
              ),

ListView has also reverse property.

like image 5
CarlosMacMar Avatar answered Oct 19 '22 18:10

CarlosMacMar


I feel your pain as it is an essential requirement because there could be tens of thousands of messages in a single chat.

To tackle that you can use

SchedulerBinding.instance.addPostFrameCallback((_){});

This callback is fired right after the widget tree is built, so you can just

scrollController.jump(scrollController.position.maxScrollExtent);

That however won't work if you have messages appear asynchronously, that is, after the initstate with some function that pulls it off from firestore document for instance. In this case you will first need for them to load, and only then do the steps above. Hope this helps.

like image 2
Zhangir Siranov Avatar answered Oct 19 '22 18:10

Zhangir Siranov