I'm currently building a calendar view in Flutter using a SliverList and a SliverChildBuilderDelegate such that I don't have to render every single item in the calendar at once.
The first date is epoch time, Jan 1, 1970, and the last date is some odd amount of time computed after today's date.
My issue is is that when I first render the view, I want it to render the view starting today, not on Jan 1, 1970. However, if I have today as the 0 indexes, negative indices are not allowed (or supplied) to the builder delegate so you can't scroll up from that date. You also can't supply an initial index, as far as I can tell, to the builder or the list, so I can't make epoch time as the 0 indexes either since the list will just start there, making for quite the terrible experience! I'm not entirely sure how to proceed.
Does anyone have any suggestions?
I'm not aware of an easy way to do this, there's no initialPositition
parameter in ListView
nor in SliverList
. The reason I can think of is that lists are a series of widgets embedded on a ScrollView
, such that in order for you to set an initial item, you would need to know the exact scroll offset of that item.
By default the two list widgets make no assumption about the height of its items, so in general finding that offset would require you to compute the heights of all widgets before it one by one, which is inefficient.
However, you can make things easier if you know beforehand the height of all your list items, or if you can force them a fixed height through either the ListView.itemExtent
field or the SliverFixedExtentList
.
In case you do know (or forced) the height of your list items beforehand, you can set an initial item through an initialScrollOffset
in your ScrollController
. Here's an example with a ListView
.
@override
Widget build(BuildContext context) {
final _itemExtent = 56.0; // I know item heights beforehand
final generatedList = List.generate(500, (index) => 'Item $index');
return ListView(
controller: ScrollController(initialScrollOffset: _itemExtent * 401),
children: generatedList
.map((index) =>
ListTile(title: Text(index, style: TextStyle(fontSize: 20.0))))
.toList(),
);
}
Or in a SliverList
.
@override
Widget build(BuildContext context) {
final _itemExtent = 56.0;
final generatedList = List.generate(500, (index) => 'Item $index');
return CustomScrollView(
controller: ScrollController(initialScrollOffset: _itemExtent * 401),
slivers: [
SliverFixedExtentList(
itemExtent: _itemExtent, // I'm forcing item heights
delegate: SliverChildBuilderDelegate(
(context, index) => ListTile(
title: Text(
generatedList[index],
style: TextStyle(fontSize: 20.0),
),
),
childCount: generatedList.length,
),
),
],
);
}
In both cases this is the result when you first open the app.