Flutter - 如何滚动到列表视图的底部?
Flutter - how to scroll to the bottom of a listview?
我使用此代码滚动:
WidgetsBinding.instance?.addPostFrameCallback((_) => _scrollToEnd());
_scrollToEnd()
方法是:
_scrollController.animateTo(
_scrollController.position.maxScrollExtent,
duration: const Duration(
milliseconds: 200,
),
curve: Curves.easeInOut,
);
将其想象成一个普通的聊天屏幕。如果消息在 1 行中,它会滚动到底部。但是一旦消息达到 2+ 行,它就很难滚动到底部。消息的行数越多,滚动到底部的次数就越少。
这是我进入聊天时的样子:
但是如果我进一步向下滚动,这是聊天的底部:
我注意到还有一种情况是:
- 我进入聊天。
- 它像第一张图片一样向下滚动。
- 如果我点击屏幕上的任意位置,它会像第二张图片一样继续滚动到列表视图的底部。
为什么会发生这种情况,我该如何解决?
我做了什么,使用 listView 和 reverse true,在儿童中使用 map.reversed 的列表,我在下面给你我的代码示例。
ListView(
reverse: true,
children: controller.listMessageData.reversed
.map((e) => Container(child: Text(e.title));
使用 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),
);
}
});
}
这只是一种解决方法,但它应该会按预期工作。在列表视图中使用夹紧物理。最大范围加个数
_scrollController.animateTo(
_scrollController.position.maxScrollExtent+300,
duration: const Duration(
milliseconds: 200,
),
curve: Curves.easeInOut,
);
使用应该反过来使用属性.
ListView.builder(
reverse: true,
itemCount: 10,
itemBuilder: (_, index) {
return ListTile(title: Text(index.toString()));
},
)
当我不得不在其展开时向项目添加滚动时,我遇到了类似的问题。
我的猜测是您在将新元素添加到列表时在同一构建中调用 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();
});
代码有点乱,希望对你有帮助
我终于找到了解决办法。 None 个答案对我有用,或部分有用,但我感谢您尝试回答。
对我来说,我所要做的就是把
reverse: true
在 ListView 构建器中,然后每当您 return 您需要的消息时 return 将其作为:
return messages[messages.length - 1 - index];
这是最重要的部分。
我使用此代码滚动:
WidgetsBinding.instance?.addPostFrameCallback((_) => _scrollToEnd());
_scrollToEnd()
方法是:
_scrollController.animateTo(
_scrollController.position.maxScrollExtent,
duration: const Duration(
milliseconds: 200,
),
curve: Curves.easeInOut,
);
将其想象成一个普通的聊天屏幕。如果消息在 1 行中,它会滚动到底部。但是一旦消息达到 2+ 行,它就很难滚动到底部。消息的行数越多,滚动到底部的次数就越少。
这是我进入聊天时的样子:
但是如果我进一步向下滚动,这是聊天的底部:
我注意到还有一种情况是:
- 我进入聊天。
- 它像第一张图片一样向下滚动。
- 如果我点击屏幕上的任意位置,它会像第二张图片一样继续滚动到列表视图的底部。
为什么会发生这种情况,我该如何解决?
我做了什么,使用 listView 和 reverse true,在儿童中使用 map.reversed 的列表,我在下面给你我的代码示例。
ListView(
reverse: true,
children: controller.listMessageData.reversed
.map((e) => Container(child: Text(e.title));
使用 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),
);
}
});
}
这只是一种解决方法,但它应该会按预期工作。在列表视图中使用夹紧物理。最大范围加个数
_scrollController.animateTo(
_scrollController.position.maxScrollExtent+300,
duration: const Duration(
milliseconds: 200,
),
curve: Curves.easeInOut,
);
使用应该反过来使用属性.
ListView.builder(
reverse: true,
itemCount: 10,
itemBuilder: (_, index) {
return ListTile(title: Text(index.toString()));
},
)
当我不得不在其展开时向项目添加滚动时,我遇到了类似的问题。 我的猜测是您在将新元素添加到列表时在同一构建中调用 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();
});
代码有点乱,希望对你有帮助
我终于找到了解决办法。 None 个答案对我有用,或部分有用,但我感谢您尝试回答。
对我来说,我所要做的就是把
reverse: true
在 ListView 构建器中,然后每当您 return 您需要的消息时 return 将其作为:
return messages[messages.length - 1 - index];
这是最重要的部分。