Flutter - 如何滚动到列表视图的底部?

Flutter - how to scroll to the bottom of a listview?

我使用此代码滚动:

WidgetsBinding.instance?.addPostFrameCallback((_) => _scrollToEnd());

_scrollToEnd()方法是:

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

将其想象成一个普通的聊天屏幕。如果消息在 1 行中,它会滚动到底部。但是一旦消息达到 2+ 行,它就很难滚动到底部。消息的行数越多,滚动到底部的次数就越少。

这是我进入聊天时的样子:

但是如果我进一步向下滚动,这是聊天的底部:

我注意到还有一种情况是:

  1. 我进入聊天。
  2. 它像第一张图片一样向下滚动。
  3. 如果我点击屏幕上的任意位置,它会像第二张图片一样继续滚动到列表视图的底部。

为什么会发生这种情况,我该如何解决?

我做了什么,使用 listView 和 reverse true,在儿童中使用 map.reversed 的列表,我在下面给你我的代码示例。

ListView(
          reverse: true,
          children: controller.listMessageData.reversed
           .map((e) => Container(child: Text(e.title));

使用 ScrollController,因为它工作流畅且易于使用

ScrollController _scrollController = new ScrollController();

像这样将控制器添加到 LisView :

 ListView.builder(controller: _scrollController,)

在您的 initState 中导航到此屏幕时滚动到底部

  @override
  void initState() {
    super.initState();

    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (_scrollController.hasClients) {
        _scrollController.animateTo(
          _scrollController.position.maxScrollExtent,
          curve: Curves.easeOut,
          duration: const Duration(milliseconds: 500),
        );
      }
    });
}

这只是一种解决方法,但它应该会按预期工作。在列表视图中使用夹紧物理。最大范围加个数

 _scrollController.animateTo(
 _scrollController.position.maxScrollExtent+300,
 duration: const Duration(
   milliseconds: 200,
  ),
  curve: Curves.easeInOut,
  );

使用应该反过来使用属性.

ListView.builder(
  reverse: true,
  itemCount: 10,
  itemBuilder: (_, index) {
    return ListTile(title: Text(index.toString()));
  },
)

当我不得不在其展开时向项目添加滚动时,我遇到了类似的问题。 我的猜测是您在将新元素添加到列表时在同一构建中调用 animate ,因此最大滚动范围在元素呈现后发生变化,并且您滚动到上一个或类似的元素。我所做的是用更新的位置值连续几次调用 scrollExtent。

代码如下:

  static const int tickCount = 8;
  int i = 0;

  Future<void> _scrollToEnd() async {
    if (mounted && tickCount > i) {
      final ScrollPosition position = Scrollable.of(context).position;

      final double target = position.pixels +
          (position.maxScrollExtent - position.pixels) / (tickCount - i);

      position.moveTo(
        target,
        duration: duration,
        curve: Curves.linear,
      );
      await Future.delayed(duration);

      i++;
      WidgetsBinding.instance.addPostFrameCallback((_) => _scrollToItem());
    }
  }

并且在第一次启动时重置我状态:

   WidgetsBinding.instance.addPostFrameCallback((_) {
                  i = 0;
                  _scrollToItem();
   });

代码有点乱,希望对你有帮助

我终于找到了解决办法。 None 个答案对我有用,或部分有用,但我感谢您尝试回答。

对我来说,我所要做的就是把

reverse: true

在 ListView 构建器中,然后每当您 return 您需要的消息时 return 将其作为:

return messages[messages.length - 1 - index];

这是最重要的部分。