我希望列表视图以偏移量开头。我正在尝试通过在ListView中使用以下代码来实现这一点。
控制器:ScrollController(initialScrollOffset:30 * ITEM_HEIGHT),
首先在第一次加载时以正确的偏移量加载列表。
通过从父窗口小部件调用set状态再次构建列表时,列表会更新,但是滚动偏移的行为很奇怪。
有两种情况:
是因为我滚动时会保留最后一个滚动位置,这会抵消我的计算结果吗?我认为这不应该发生,因为它是状态少的小部件。
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;
}
}
答案 0 :(得分:2)
我接触了Flutter Slack社区,并得到了可行的答案。全部归功于楼首。这是谈话内容的副本。
ScrollController
将其滚动位置保存在其所附的列表的PageStorage
记录内……而不是它自己的PageStorage。因此,在重新创建窗口小部件时,由于您没有为列表视图窗口小部件指定新的key
,因此它会重用相同的键(为提高性能而进行内部优化的众多优化之一)。您可以通过添加两行来解决此问题:
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;
}
}
答案 1 :(得分:0)
更多代码可能会有所帮助,尽管看起来您是在build方法内部实例化ScrollController。生成方法会不断重建。因此,它将不断使用该initialScrollOffset。尝试在主要build方法之外实例化ScrollController。
修改 添加新代码后,我认为这是您的罪魁祸首:
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),
),
);
});
在重建无状态窗口小部件时,似乎好像是在生成列表,这可能有一些奇怪的行为。我认为该类需要放在有状态的小部件中,而应该在initState上生成数据列表,或者可以从诸如继承的小部件之类的其他位置获取该数据,或使用某种架构模式来保存此数据(BLoC或其他任何内容) )。
答案 2 :(得分:0)
真正的问题出在您的Day
小部件上,我不知道它的代码,因此我删除了此部分,并使用普通的ListTile
进行了工作,并且按预期运行。试试下面的代码(所有内容都与您输入的内容完全相同,我只是删除了Day
小部件部分)
class DaysManager extends StatelessWidget {
final int daysBeforeFocusDate = 30;
final int totalDaysToInit = 61;
static final double ITEM_HEIGHT = 108.00;
ScrollController scrollController;
DaysManager({DateTime focusDate}) {
scrollController = ScrollController(initialScrollOffset: 30 * ITEM_HEIGHT);
}
@override
Widget build(BuildContext context) {
return _buildScrollView();
}
ListView _buildScrollView() {
ListView listView = ListView.builder(
cacheExtent: 0,
controller: scrollController,
itemCount: 1000,
itemBuilder: (BuildContext context, int index) {
return ListTile(title: Text("Item ${index}"),);
},
);
return listView;
}
}