I want to use Wrap on large amount of objects.
I tried to just map all object to children but it cause serious performance issue.
I want some alternative way to build only currently displayed widgets but with style of Wrap.
Some code:
Wrap(
children: list.map(createCardFromData), // List contains 20'000 items
);
CodePudding user response:
This is also something which is being discussed on Flutter's repo
Please use flutter run --no-sound-null-safety
as one of the library is not null-safe. Also, you might find lag as lots of svgs are being processed on scroll. It might not happen in production.
CodePudding user response:
Do you need this many items loaded at once? You're probably using a scroll view anyway, so the user only initially sees a small batch of items rather than all of them, until they actually scroll for more. What you're looking for is lazy loading, maybe combined with a technique like infinite scroll.
Try a ListView
(specifically, ListView.builder
) where each item contains a Wrap
widget (say, each 10 items - but you may want to experiment with this number until you see a balance between performance and visual appeal).
Or, alternatively, you may code your own Wrap
that does loading lazily and reuses its views, so that it only loads and displays a couple of its children as needed, not thousands at once.
CodePudding user response:
If your items are fixed width you could try something like this:
import 'dart:math';
import 'package:flutter/cupertino.dart';
typedef ValueWidgetBuilder<T> = Widget Function(T value);
class WrapBuilder extends StatelessWidget {
final double itemWidth;
final List items;
final ValueWidgetBuilder itemBuilder;
const WrapBuilder(
{Key? key,
required this.itemWidth,
required this.items,
required this.itemBuilder})
: super(key: key);
@override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, constraints) {
var cardsPerRow = max(1, constraints.maxWidth ~/ itemWidth);
return ListView.builder(
shrinkWrap: true,
controller: ScrollController(),
itemCount: (items.length / cardsPerRow).ceil(),
itemBuilder: (BuildContext context, int index) {
var rowItems = items.sublist(cardsPerRow * index,
min(cardsPerRow * (index 1), items.length));
return Row(children: [
for (final item in rowItems)
SizedBox(
width: itemWidth,
child: itemBuilder(item))
]);
},
);
});
}
}
And then use like
WrapBuilder(
itemWidth: 100, //example
items: list,
itemBuilder: createCardFromData);