infinite_lazy_grid 1.0.3 copy "infinite_lazy_grid: ^1.0.3" to clipboard
infinite_lazy_grid: ^1.0.3 copied to clipboard

infinitely scrollable and zoomable grid layout with lazy loading capabilities.

infinite_lazy_grid #

Infinite zoomable, pannable 2D canvas using spatial hash for only rendering what's visible.

Example: https://infinite-lazy-grid.pages.dev/

Quick Start #

import 'package:flutter/material.dart';
import 'package:infinite_lazy_grid/infinite_lazy_grid.dart';

class DemoCanvas extends StatefulWidget {
  const DemoCanvas({super.key});
  @override
  State<DemoCanvas> createState() => _DemoCanvasState();
}

class _DemoCanvasState extends State<DemoCanvas> {
  // all interactions go through the controller
  final controller = LazyCanvasController(
    background: const DotGridBackground(),
    debug: true, // wraps each child with debug info visible on screen (positions, id)
  );

  @override
  void initState() {
    super.initState();
    // Add some sample nodes in a grid
    for (int i = 0; i < 50; i++) {
      controller.addChild(
        Offset((i % 10) * 140.0, (i ~/ 10) * 140.0),
        Container(
          width: 100,
          height: 100,
          color: Colors.primaries[i % Colors.primaries.length],
          alignment: Alignment.center,
          child: Text('${i + 1}', style: const TextStyle(color: Colors.white)),
        ),
      );
    }
  }

  @override
  Widget build(BuildContext ctx) {
    return Scaffold(
      appBar: AppBar(title: const Text('infinite_lazy_grid')),
      // pass the controller to the LazyCanvas widget
      body: LazyCanvas(controller: controller),
    );
  }
}

Usage #

Adding/Removing children #

// one child, returns its id which is just a uuid string
CanvasChildId oneChild = controller.addChild(
  const Offset(500, 1200),
  const Icon(Icons.place, size: 32),
);

// with custom widget
List<CanvasChildId> batchAdd = controller.addChildren([
  CanvasChildArgs(position: const Offset(0, 0), widget: const Text('Origin')),
  CanvasChildArgs(position: const Offset(800, 200), widget: const Icon(Icons.star)),
]);

// remove one by Id
controller.removeChild(oneChild);

// remove all
controller.clear();

Focus / center #

All of these animate by default (duration optional, animate: false to jump).

// child specific
controller.focusOnChild(id);                                   // keep scale
controller.focusOnChild(id, scalingMode: ScalingMode.resetScale);
controller.focusOnChild(id, scalingMode: ScalingMode.fitInViewport, preferredHorizontalMargin: 16);

// absolute position in grid space
controller.centerOnGridOffset(const Offset(0, 0));

// absolute position in screen space
controller.centerOnScreenOffset(const Offset(200, 150));

Zoom & animate #

controller.updateScalebyDelta(0.2);      // zoom in
controller.updateScalebyDelta(-0.2);     // zoom out
// animate to position on grid
await controller.animateToOffsetAndScale(
  offset: const Offset(1200, 300),
  scale: 2.0,
  duration: const Duration(milliseconds: 400),
);

Background options #

background: const NoBackground();
background: const SingleColorBackround(Colors.white);
background: const DotGridBackground(spacing: 60, size: 2.0);

All of these implement abstract class CanvasBackground so you can add your own.

Render callbacks #

LazyCanvasController(
  onWidgetEnteredRender: (id) { /* do something */ },
  onWidgetExitedRender: (id) { /* do something else */ },
);

Widget updates #

Since the args aren't directly available for you to place in the build tree, child rebuilds can be handled in three ways:

  1. Stateful widget child: Child handles its own updates but state is lost when unmounted.
  2. Manual update: updateChildWidget(id, newWidget).
  3. Child listens to external state: Some Listenable or a state management library like Provider, etc., that rebuilds the child when data changes.

Size based optimisations #

focusOnChild auto measures offstage if size unknown. Provide childSize if you already know it to skip the extra pass.

This extra pass is cached so would only happen once per child if size not provided.

Example #

See example/ directory (Simple Example, Build Counts Example, Widget State Updates Example, Render Callbacks Example).

7
likes
150
points
223
downloads

Publisher

unverified uploader

Weekly Downloads

infinitely scrollable and zoomable grid layout with lazy loading capabilities.

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

flutter, uuid

More

Packages that depend on infinite_lazy_grid