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 包 )