我有一个可滚动的ListView,其中项目的数量可以动态变化。每当一个新项目被添加到列表的末尾时,我希望以编程的方式将ListView滚动到末尾。(例如,类似聊天消息列表的东西,可以在最后添加新消息)
我的猜测是,我需要在我的State对象中创建一个ScrollController,并手动将其传递给ListView构造函数,这样我就可以稍后在控制器上调用animateTo() / jumpTo()方法。然而,由于我不容易确定最大滚动偏移量,因此似乎不可能简单地执行scrollToEnd()类型的操作(而我可以轻松地传递0.0使其滚动到初始位置)。
有没有简单的方法来实现这个目标?
使用reverse: true对我来说不是一个完美的解决方案,因为当只有少量的项目适合ListView视口时,我希望项目在顶部对齐。
我的解决方案:
1 .
像这样定义全局键:
final lastKey = GlobalKey();
2 .
附加到最后一条消息
SingleChildScrollView(
controller: scrollController,
padding: const EdgeInsets.fromLTRB(10, 10, 10, 10),
physics: const AlwaysScrollableScrollPhysics(),
child: Column(
children: List.generate(
data.length,
(index) {
return BuildMessage(
key:
data.length == index + 1 ? lastKey : null,
message: data[index],
focusNode: focusNode,
);
},
),
),
)
3 .
创建滚动的函数调用
void scrollToBottom() {
Scrollable.ensureVisible(lastKey.currentContext!,alignment: 1, duration: const Duration(milliseconds: 500));
}
当你想滚动到底部时调用,延迟100毫秒
Timer(const Duration(milliseconds: 100),() => scrollToBottom());
我的解决方案:
1 .
像这样定义全局键:
final lastKey = GlobalKey();
2 .
附加到最后一条消息
SingleChildScrollView(
controller: scrollController,
padding: const EdgeInsets.fromLTRB(10, 10, 10, 10),
physics: const AlwaysScrollableScrollPhysics(),
child: Column(
children: List.generate(
data.length,
(index) {
return BuildMessage(
key:
data.length == index + 1 ? lastKey : null,
message: data[index],
focusNode: focusNode,
);
},
),
),
)
3 .
创建滚动的函数调用
void scrollToBottom() {
Scrollable.ensureVisible(lastKey.currentContext!,alignment: 1, duration: const Duration(milliseconds: 500));
}
当你想滚动到底部时调用,延迟100毫秒
Timer(const Duration(milliseconds: 100),() => scrollToBottom());
_controller.jumpTo(_controller.position.maxScrollExtent);
_controller.animateTo(_controller.position.maxScrollExtent);
这些调用不能很好地用于动态大小的项列表。在调用jumpTo()时,我们不知道列表有多长,因为所有的项都是变量,并且是在向下滚动列表时惰性构建的。
这可能不是聪明的方法,但作为最后的手段,你可以这样做:
Future scrollToBottom(ScrollController scrollController) async {
while (scrollController.position.pixels != scrollController.position.maxScrollExtent) {
scrollController.jumpTo(scrollController.position.maxScrollExtent);
await SchedulerBinding.instance!.endOfFrame;
}
}