Programmatically scrolling to the end of a ListView

前端 未结 7 1927
既然无缘
既然无缘 2020-11-27 13:03

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 programmatic

相关标签:
7条回答
  • 2020-11-27 13:34

    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,
    );
    
    0 讨论(0)
  • 2020-11-27 13:40

    If you use a shrink-wrapped ListView with reverse: true, scrolling it to 0.0 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),
              );
            }
          ),
        );
      }
    }
    
    0 讨论(0)
  • 2020-11-27 13:43

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

    0 讨论(0)
  • 2020-11-27 13:48

    Do not put the widgetBinding in the initstate, instead, you need to put it in the method that fetches your data from database. for example, like this. If put in initstate, the scrollcontroller will not attach to any listview.

        Future<List<Message>> fetchMessage() async {
    
        var res = await Api().getData("message");
        var body = json.decode(res.body);
        if (res.statusCode == 200) {
          List<Message> messages = [];
          var count=0;
          for (var u in body) {
            count++;
            Message message = Message.fromJson(u);
            messages.add(message);
          }
          WidgetsBinding.instance
              .addPostFrameCallback((_){
            if (_scrollController.hasClients) {
              _scrollController.jumpTo(_scrollController.position.maxScrollExtent);
            }
          });
          return messages;
        } else {
          throw Exception('Failed to load album');
        }
       }
    
    0 讨论(0)
  • 2020-11-27 13:52

    you could use this where 0.09*height is the height of a row in the list and _controller is defined like this _controller = ScrollController();

    (BuildContext context, int pos) {
        if(pos != 0) {
            _controller.animateTo(0.09 * height * (pos - 1), 
                                  curve: Curves.easeInOut,
                                  duration: Duration(milliseconds: 1400));
        }
    }
    
    0 讨论(0)
  • 2020-11-27 13:58

    to get the perfect results I combined Colin Jackson and CopsOnRoad's answers as follows:

    _scrollController.animateTo(
                                  _scrollController.position.maxScrollExtent,
                                  curve: Curves.easeOut,
                                  duration: const Duration(milliseconds: 500),
                                );
    
    0 讨论(0)
提交回复
热议问题