我有一个可滚动的ListView,其中项目的数量可以动态变化。每当一个新项目被添加到列表的末尾时,我希望以编程的方式将ListView滚动到末尾。(例如,类似聊天消息列表的东西,可以在最后添加新消息)

我的猜测是,我需要在我的State对象中创建一个ScrollController,并手动将其传递给ListView构造函数,这样我就可以稍后在控制器上调用animateTo() / jumpTo()方法。然而,由于我不容易确定最大滚动偏移量,因此似乎不可能简单地执行scrollToEnd()类型的操作(而我可以轻松地传递0.0使其滚动到初始位置)。

有没有简单的方法来实现这个目标?

使用reverse: true对我来说不是一个完美的解决方案,因为当只有少量的项目适合ListView视口时,我希望项目在顶部对齐。


当前回答

根据这个答案,我已经创建了这个类,只是发送你的scroll_controller,如果你想要相反的方向使用反向参数

import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';

class ScrollService {
  static scrollToEnd(
      {required ScrollController scrollController, reversed = false}) {
    SchedulerBinding.instance!.addPostFrameCallback((_) {
      scrollController.animateTo(
        reverced
            ? scrollController.position.minScrollExtent
            : scrollController.position.maxScrollExtent,
        duration: const Duration(milliseconds: 300),
        curve: Curves.easeOut,
      );
    });
  }
}

其他回答

listViewScrollController.animateTo(listViewScrollController.position.maxScrollExtent)是最简单的方法。

我使用的是一个动态列表视图,但scrollController.animateTo()不会工作在这里提到的动态列表https://stackoverflow.com/a/67561421/13814518,我甚至没有在以前的答复中找到任何好的解决方案。下面是我解决这个问题的方法。

void scrollToMaxExtent() {
  WidgetsBinding.instance.addPostFrameCallback((_) {
    scrollController.animateTo(
      scrollController.position.maxScrollExtent,
      duration: const Duration(milliseconds: 100),
      curve: Curves.easeIn,
    );
  });
}

你可以使用0.09*height作为列表中一行的高度,_controller的定义如下:_controller = ScrollController();

(BuildContext context, int pos) {
    if(pos != 0) {
        _controller.animateTo(0.09 * height * (pos - 1), 
                              curve: Curves.easeInOut,
                              duration: Duration(milliseconds: 1400));
    }
}

根据这个答案,我已经创建了这个类,只是发送你的scroll_controller,如果你想要相反的方向使用反向参数

import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';

class ScrollService {
  static scrollToEnd(
      {required ScrollController scrollController, reversed = false}) {
    SchedulerBinding.instance!.addPostFrameCallback((_) {
      scrollController.animateTo(
        reverced
            ? scrollController.position.minScrollExtent
            : scrollController.position.maxScrollExtent,
        duration: const Duration(milliseconds: 300),
        curve: Curves.easeOut,
      );
    });
  }
}

为了得到完美的结果,我将Colin Jackson和CopsOnRoad的答案结合如下:

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