ListVIew 再次构建后不会滚动到正确的偏移位置
Posted
技术标签:
【中文标题】ListVIew 再次构建后不会滚动到正确的偏移位置【英文标题】:ListVIew doesn't scroll to the correct offset position after its built again 【发布时间】:2019-10-15 07:47:33 【问题描述】:我希望列表视图以偏移量开始。我试图通过在 ListView 中使用以下代码来实现。
控制器:ScrollController(initialScrollOffset: 30 * ITEM_HEIGHT),
最初在第一次加载时,列表会加载正确的偏移量。
当通过从父小部件调用 set state 再次构建列表时,列表会更新,但滚动偏移量的行为很奇怪。
有两种情况:
-
我不滚动列表:在此之后,如果调用设置状态,一切正常。列表得到更新,并且始终处于正确的偏移量。
我滚动列表:如果我滚动列表然后重建列表,
滚动偏移量减少了几项。列表得到更新,这很好。
是因为当我滚动时它保持最后滚动位置并且抵消了我的计算?我认为这不应该发生,因为它是一个无状态的小部件。
class DaysManager extends StatelessWidget
final int daysBeforeFocusDate = 30;
final int totalDaysToInit = 61;
static final double ITEM_HEIGHT = 108.00;
ScrollController scrollController;
List<Day> days;
DaysManager(DateTime focusDate)
final DateTime startDate =
focusDate.subtract(Duration(days: daysBeforeFocusDate));
days = List.generate(totalDaysToInit, (int index)
return Day(
date: startDate.add(
Duration(days: index),
),
);
);
scrollController = ScrollController(initialScrollOffset: 30 *ITEM_HEIGHT);
@override
Widget build(BuildContext context)
return _buildScrollView();
ListView _buildScrollView()
ListView listView = ListView.builder(
cacheExtent: 0,
controller: scrollController,
itemCount: days.length,
itemBuilder: (BuildContext context, int index)
return days[index];
);
return listView;
【问题讨论】:
你在哪里有这个scrollController = ScrollController(initialScrollOffset: 30 *ITEM_HEIGHT);
?直接在类或方法中?
我已经添加了代码。请看那里。
【参考方案1】:
我联系了 Flutter Slack 社区并得到了有效的答案。都归功于楼上那边。这是那次谈话的副本。
ScrollController
将其滚动位置保存在 它所附加到的列表的PageStorage
记录中……而不是它自己的 PageStorage。因此,当重新创建小部件时,由于您没有为 listview 小部件指定新的key
,它会重用相同的键(flutter 内部的许多优化之一以提高性能)。你可以通过添加两行来解决这个问题:
import 'dart:math';
...
ListView listView = ListView.builder(
key: ValueKey<int>(Random(DateTime.now().millisecondsSinceEpoch).nextInt(4294967296)),
...
每次重新创建列表视图时,您都需要给它一个新的随机 key
,这样它就不会加载它的 PageStorage
值。
这是您的示例代码中DaysManager
的完整更新代码:
class DaysManager extends StatelessWidget
final int daysBeforeFocusDate = 30;
final int totalDaysToInit = 61;
static final double ITEM_HEIGHT = 108.00;
ScrollController scrollController;
List<Day> days;
DaysManager(
DateTime focusDate,
)
final DateTime startDate = focusDate.subtract(Duration(days: daysBeforeFocusDate));
days = List.generate(totalDaysToInit, (int index)
return Day(
date: startDate.add(
Duration(days: index),
),
);
);
scrollController = ScrollController(
initialScrollOffset: 30 *ITEM_HEIGHT,
);
@override
Widget build(BuildContext context)
return _buildScrollView();
ListView _buildScrollView()
ListView listView = ListView.builder(
key: ValueKey<int>(Random(DateTime.now().millisecondsSinceEpoch).nextInt(4294967296)),
cacheExtent: 0,
controller: scrollController,
itemCount: days.length,
itemBuilder: (BuildContext context, int index)
return days[index];
);
return listView;
【讨论】:
一旦我意识到我们不想在两次绘制之间保持滚动位置,而是想将其重置到新选定项目的顶部(正好在 30 下清单),我理解了问题并创建了解决方案。然后我解释了为什么这是解决方案。感谢@will-luce 的支持 哇,这太棒了。最后我们得到了解决这个问题的办法。感谢您的回答。 虽然我需要了解PageStorage是什么以及它是如何工作的,它存储了什么样的信息。如果您了解更多请做解释。 PageStorage 保存了许多 Flutter 核心小部件上各种数据的键值对。您甚至可以将它用于您自己的小部件。不过,这一切都基于小部件的 Key 。将其视为特定于每个有状态小部件的数据的全局存储空间。它允许您保留小部件的数据,即使完全销毁小部件,只要您使用相同的 Key。在很多方面,它就像 Flutter 的内部状态管理。这是一个关于 Keys 的好视频youtube.com/watch?v=kn0EOS-ZiIc ...还有一篇关于PageStorage的文章steemit.com/utopian-io/@tensor/…以上是关于ListVIew 再次构建后不会滚动到正确的偏移位置的主要内容,如果未能解决你的问题,请参考以下文章