Home > Back-end >  Wrap.builder like in ListView.builder
Wrap.builder like in ListView.builder

Time:11-15

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 really good example flutter is missing in my opinion.

This is also something which is being discussed on Flutter's repo Output

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);
  • Related