Programmatically Scroll to the End of a ListView

I have a scrollable ListView where the number of elements 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. (for example, something like a chat message list where new messages can be added at the end)

I assume that I will need to create a ScrollController in my State object and pass it manually to the ListView constructor, so I can later call the animateTo() / jumpTo() method on the controller. However, since I cannot easily determine the maximum scroll offset, it seems impossible to simply perform an operation like scrollToEnd() (whereas I can easily go through 0.0 to scroll to its original position).

Is there an easy way to achieve this?

Using reverse: true is not an ideal solution for me, because I would like the items to align at the top when there is only a small number of items that fit into the ListView viewport.

+45
source share
4 answers

If you use a ListView wrapper with reverse: true , scrolling it to 0.0, you will do what you want.

 import 'dart:collection'; import 'package:flutter/material.dart'; void main() { runApp(new MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return new MaterialApp( title: 'Example', home: new MyHomePage(), ); } } class MyHomePage extends StatefulWidget { @override _MyHomePageState createState() => new _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { List<Widget> _messages = <Widget>[new Text('hello'), new Text('world')]; ScrollController _scrollController = new ScrollController(); @override Widget build(BuildContext context) { return new Scaffold( body: new Center( child: new Container( decoration: new BoxDecoration(backgroundColor: Colors.blueGrey.shade100), width: 100.0, height: 100.0, child: new Column( children: [ new Flexible( child: new ListView( controller: _scrollController, reverse: true, shrinkWrap: true, children: new UnmodifiableListView(_messages), ), ), ], ), ), ), floatingActionButton: new FloatingActionButton( child: new Icon(Icons.add), onPressed: () { setState(() { _messages.insert(0, new Text("message ${_messages.length}")); }); _scrollController.animateTo( 0.0, curve: Curves.easeOut, duration: const Duration(milliseconds: 300), ); } ), ); } } 
+42
source

To do this, use ScrollController.jumpTo() or ScrollController.animateTo() .

Here is a snippet of code (after 1 second the ListView scroll down)

 class _HomePageState extends State<HomePage> { ScrollController _controller = ScrollController(); @override Widget build(BuildContext context) { Timer(Duration(milliseconds: 1000), () => _controller.jumpTo(_controller.position.maxScrollExtent)); return ListView.builder( controller: _controller, itemCount: 50, itemBuilder: (context, index) => ListTile(title: Text("ListTile"),)); } } 
+33
source

I have so many problems trying to use the scroll controller to go to the bottom of the list, and I use a different approach.

Instead of creating an event to send the list to the end, I change my logic to use the reverse list.

Thus, every time I have a new item, I just do it in the tab at the top of the list.

 // add new message at the begin of the list list.insert(0, message); // ... // pull items from the database list = await bean.getAllReversed(); // basically a method that applies a descendent order // I remove the scroll controller new Flexible( child: new ListView.builder( reverse: true, key: new Key(model.count().toString()), itemCount: model.count(), itemBuilder: (context, i) => ChatItem.displayMessage(model.getItem(i)) ), ), 
+1
source

listViewScrollController.animateTo(listViewScrollController.position.maxScrollExtent) is the easiest way.

0
source

Source: https://habr.com/ru/post/1266889/


All Articles