【问题标题】:Flutter - how to scroll to the bottom of a listview?Flutter - 如何滚动到列表视图的底部?
【发布时间】:2021-12-11 08:22:13
【问题描述】:

我使用此代码滚动:

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

_scrollToEnd()方法是:

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

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

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

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

我注意到还有一种情况:

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

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

【问题讨论】:

  • 你能包含一个列表项以及底部小部件的用途吗?
  • 请看@Alwayss Bijoy 的回答。我认为您问错了问题,而他的答案可能是您需要/想要使用的东西:)

标签: android ios flutter dart mobile


【解决方案1】:

我做了什么,使用 listView 并反向为真,在儿童中使用 map.reversed 列表,我在下面给你我的代码示例。

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

【讨论】:

    【解决方案2】:

    使用 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),
            );
          }
        });
    }
    

    【讨论】:

    • 我试过了,还是一样的问题
    【解决方案3】:

    只是一种解决方法,但它应该可以按预期工作。在列表视图中使用钳位物理。在最大范围内添加一个额外的数字

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

    【讨论】:

    • 这是迄今为止最接近的答案。它起作用了,现在它滚动到光秃秃的底部。但是我注意到,由于钳位物理,ios 上没有“拖到底部”的影响。是否可以保留这种效果?
    • 您可以将物理更改为bouncephysics 或普通的scrollphysics,但您可能会看到一个额外的反弹到最后,然后它会卡在看起来有点奇怪的位置
    • 是的,我注意到现在有反弹效果。有没有办法解决这个问题?
    • 尝试近似值相加。例如,如果最后一条消息是 4 行。添加一个值 120 (30x4)。这样你就可以使用你选择的任何物理并且它不会反弹。
    【解决方案4】:

    使用应该使用reverse属性。

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

    【讨论】:

      【解决方案5】:

      当我不得不在其展开时向项目添加滚动时,我遇到了类似的问题。 我的猜测是,您在将新元素添加到列表时调用 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();
         });
      

      代码有点乱,但我希望它有所帮助

      【讨论】:

        【解决方案6】:

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

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

        reverse: true
        

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

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

        这是最重要的部分。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-08-09
          • 1970-01-01
          • 2014-07-11
          • 1970-01-01
          • 2011-08-31
          相关资源
          最近更新 更多