简体   繁体   English

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

[英]Flutter - how to scroll to the bottom of a listview?

I use this code to scroll:我使用此代码滚动:

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

_scrollToEnd() method is: _scrollToEnd()方法是:

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

Imagine this as a normal chat screen.想象一下这是一个普通的聊天屏幕。 It scrolls to the bare bottom if the messages are in 1 line.如果消息在 1 行,它会滚动到底部。 But as soon as a message gets to 2+ lines it struggles to scroll to the bare bottom.但是,一旦消息到达 2 行以上,它就很难滚动到裸露的底部。 The more rows of a message the less it scrolls to the bottom.消息的行数越多,滚动到底部的次数就越少。

This is how it looks like when i enter the chat:这是我进入聊天时的样子:

But if i scroll down further this is the bottom of the chat:但如果我进一步向下滚动,这是聊天的底部:

I noticed there's also a case when:我注意到还有一种情况:

  1. I enter the chat.我进入聊天。
  2. It scrolls down like on the first image.它像第一张图片一样向下滚动。
  3. If i tap anywhere on the screen, it continues to scroll to the bare bottom of the listview like on the second image.如果我点击屏幕上的任何位置,它会继续滚动到列表视图的底部,就像第二张图片一样。

Why does this happen and how do i fix this?为什么会发生这种情况,我该如何解决?

what i did, use a listView and reverse true and in children use the list of map.reversed, i am giving you my code example below.我做了什么,使用 listView 并反转 true,在儿童中使用 map.reversed 列表,我在下面给你我的代码示例。

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

Use ScrollController for that it works smooth and simple to use使用 ScrollController 因为它运行流畅且易于使用

ScrollController _scrollController = new ScrollController();

Add controller to LisView like this :像这样将控制器添加到 LisView:

 ListView.builder(controller: _scrollController,)

In your initState to scroll to bottom when navigating to this screen在您的 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),
        );
      }
    });
}

Just a workaround but it should work as expected.只是一种解决方法,但它应该按预期工作。 Use clamping physics in the list view.在列表视图中使用夹紧物理。 Add an extra number to the max extent添加一个额外的数字到最大范围

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

Use should use the reverse property.使用时应使用 reverse 属性。

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

i had a similar problem when i had to add scroll to item on its expand.当我不得不在展开时向项目添加滚动时,我遇到了类似的问题。 my guess is that you call animate to in the same build as when adding new elements to list, so the maximum scroll extent changes after the render of the element, and you scroll to previous one, or smth similar.我的猜测是,您在将新元素添加到列表时在同一构建中调用 animate ,因此最大滚动范围在元素渲染后发生变化,并且您滚动到前一个或类似的内容。 what i did was to call scrollExtent few consecutive times with updated position value.我所做的是使用更新的位置值连续几次调用 scrollExtent 。

the code goes like this:代码是这样的:

  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());
    }
  }

and on first launch reset i state:在第一次启动重置时,我声明:

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

code is a bit messy but i hope it helps代码有点乱,但我希望它有帮助

I finally found a solution.我终于找到了解决方案。 None of the answers worked for me, or worked partially, but I appreciate your attempts to answer.没有一个答案对我有用,或者部分有用,但我感谢您尝试回答。

For me all i had to do was put对我来说,我所要做的就是把

reverse: true

in the ListView builder and then whenever you return the message you need to return it as:在 ListView 构建器中,然后每当您返回消息时,您需要将其返回为:

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

This is the most important part.这是最重要的部分。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM