Flutter - ListView.builder:初始滚动位置

Posted

技术标签:

【中文标题】Flutter - ListView.builder:初始滚动位置【英文标题】:Flutter - ListView.builder: Initial scroll position 【发布时间】:2019-12-21 13:30:12 【问题描述】:

我想设置 ListView.builder 的初始滚动位置,我希望列表从底部开始0.0

如果我在 listView 上设置reverse,我当然会得到所需的初始滚动位置,但我需要的是让最后一个孩子位于底部,这是一个聊天应用程序。

这是列表生成器,MessageItem() 是聊天消息

ListView.builder(
                    shrinkWrap: true,
                    controller: _scrollController,
                    itemCount: snapshot.data.documents.length,
                    padding: EdgeInsets.all(10.0),
                    itemBuilder: (BuildContext context, int index) =>
                        MessageItem(
                            index: index,
                            document: snapshot.data.documents[index],
                            myId: myId));

这是有人send留言时我的动画


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

动画效果不错。


我想要的是当用户进入聊天室时列表滚动位置已经在底部。

【问题讨论】:

使用 0 毫秒的持续时间会起作用吗? 为什么不在小部件的 initState 中设置滚动控制器的初始位置。这样在初始小部件构建中它会滚动到底部位置。 @E.Bradford 好吧,这只是当用户按下“发送消息”按钮时发生的动画,它有效。我尝试将动画代码放在initState() 上,但它会抛出错误:``` I/flutter (15097): ScrollController not attach to any scroll views。 I/flutter (15097): 'package:flutter/src/widgets/scroll_controller.dart': I/flutter (15097): 断言失败: line 110 pos 12: '_positions.isNotEmpty' ``` 我应该把它放在哪里可以一开始就触发吗? @Salma。试过了,我得到一个错误。 在初始化 scrollController 时将其设置为 0.0 >>> _scrollController = new ScrollController( initialScrollOffset: 0.0, keepScrollOffset: true, ); 【参考方案1】:

您可以设置ScrollController's 属性之一:initialScrollOffset

但前提是你知道目标项/索引的偏移位置。

ScrollController _controller = ScrollController(initialScrollOffset: itemHeight * index)

(请注意,此示例假定列表小部件的大小是恒定的,但如果列表中没有恒定的小部件大小,那么您必须能够计算最终的偏移位置您的目标项目 - 这是另一个问题

或者,如果您希望它始终是最后一个项目/索引,那么它会容易得多:

ScrollController _controller = ScrollController(initialScrollOffset: _controller.position.maxScrollExtent)

【讨论】:

构建时不能使用_controller @maff 因为有一个特殊的方法 - addpostframecallback,它在构建小部件树后立即触发,因此您不必猜测 initstate 的延迟。 @maff 同意你的观点,但你可以检查一下if(_controller.hasClients) <Then Scroll to desired positon> initialOffset 不会动画到该位置【参考方案2】:

为避免任何列表未附加滚动的错误,请使用 WidgetsBinding 在构建准备好后拉出。


void _scrollToBottom() 
    if (_scrollController.hasClients) 
      _scrollController.animateTo(_scrollController.position.maxScrollExtent,
          duration: Duration(milliseconds: 300), curve: Curves.elasticOut);
     else 
      Timer(Duration(milliseconds: 400), () => _scrollToBottom());
    
 

@override
Widget build(BuildContext context) 

  WidgetsBinding.instance.addPostFrameCallback((_) => _scrollToBottom());

  ... //rest of code;

【讨论】:

不知道为什么这个答案没有得到更多的爱。这解决了我在 ListView 中选择复选框并保持视图静态而不是总是跳回顶部时遇到的问题。谢谢!【参考方案3】:

我的解决方案是:

SingleChildScrollView(
                reverse: true,
                child: Container(),
              ),

ListView 也有 reverse 属性。

【讨论】:

你也应该反转你的数组消息。【参考方案4】:

我感受到你的痛苦,因为这是一项基本要求,因为一次聊天中可能会有数万条消息。

要解决这个问题,您可以使用

SchedulerBinding.instance.addPostFrameCallback((_));

这个回调是在构建小部件树后立即触发的,所以你可以

scrollController.jump(scrollController.position.maxScrollExtent);

但是,如果您的消息是异步显示的,即在 initstate 之后使用某些函数将其从 firestore 文档中提取出来,那么这将不起作用。 在这种情况下,您首先需要加载它们,然后才执行上述步骤。希望这会有所帮助。

【讨论】:

【参考方案5】:

有一些简单的假设,即您在未来的构建器中从 API 获取列表并返回 listview.builder

snapshot.data.length-index-1

从 listview.builder 中移除 reverse 属性

【讨论】:

以上是关于Flutter - ListView.builder:初始滚动位置的主要内容,如果未能解决你的问题,请参考以下文章

Xcode 13 和 Flutter 2.5.1 - 致命错误:找不到“Flutter/Flutter.h”文件 #import <Flutter/Flutter.h>

Flutter 致命错误:找不到“Flutter/Flutter.h”文件

[Flutter] flutter项目一直卡在 Running Gradle task 'assembleDebug'...

flutter 日志输出,Flutter打印日志,flutter log,flutter 真机日志

Flutter开发 Flutter 包和插件 ( Flutter 包和插件简介 | 创建 Flutter 插件 | 创建 Dart 包 )

flutter与原生混编(iOS)