I would like to create a simple grid of images categorized by headers. The images are contained in a custom widget (for showing a name etc. below each image). So far the most straightforward way seemed to be using the sticky_headers package and basically creating a list of grids with individual headers for each grid. Here is the simplified code I wrote for that:
ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
var category = items.entries.elementAt(index);
var header = category.key;
var categoryItems = category.value.entries;
return StickyHeader(
header: Text(header);
content: LayoutBuilder(
builder: (context, constraints) => GridView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: categoryItems.length,
itemBuilder: (context, index) => CustomCardWidget(
item: categoryItems.elementAt(index)
image: _getItemImage(categoryItems.elementAt(index).key),
),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
),
),
);
},
)
And the function used for loading images. I hate it and it might be the problem (which is why I'm including it here) but I haven't been able to find any alternatives (since I don't know whether there is an image available for a given item, I might have to create a lookup in case there's no real way to check this at runtime, but that doesn't seem ideal either):
// based on: https://stackoverflow.com/a/71037750/13215204
Future<Image> _getItemImage(String imageName) async {
try {
await DefaultAssetBundle.of(context).load('$imageName.png');
return Image.asset('$imageName.png');
} catch (_) {
return const Image(image: AssetImage('default.png'));
}
}
This works, but the performance is abysmal. The images get reloaded every time the widget gets build, so a lot. As far as I understand, the problem is flutter not being able to properly optimize a grid inside a list view, since the images aren't direct children of the list. The whole concept of inflating a scroll view as a child of another one and then setting physics: const NeverScrollableScrollPhysics()
to prevent the whole thing from breaking down just seems really messy as well. I've looked into the sticky_grid_view package which seems to resolve the issue by allowing for a single grid containing everything and properly caching the images. But sadly, it does not allow me to specify a custom container for the images.
To recap, here are my ideas on this so far:
- Maybe there's a package out there already achieving this
- Should I load all the images on startup?
- Can increasing the cache size prevent the images from being reloaded on build?
- Is the whole try-catch abomination causing the performance problems?
- Do I need to specify something to let flutter know the card does not need to be refreshed, or is this just inevitable (and probably desirable) with how scroll views un- and reload elements to optimize performance?
Any thoughts on this? I'm not expecting a finished code snipped, but any ideas would be appreciated since I don't really know where to go from here. Btw., I'm completely new to flutter and still trying to wrap my head around the basic concepts, so my apologies if there's some pretty nonsensical stuff in here