kinetic_gallery 0.1.2
kinetic_gallery: ^0.1.2 copied to clipboard
Gesture-driven Flutter galleries featuring dynamic hero carousels and virtualized, zoomable infinite masonry spaces.
Kinetic Gallery #
Interactive card layouts for Flutter: a dynamically sized Hero Carousel and a zoomable infinite masonry space. Content is supplied by your widgets; the core package depends only on Flutter.
0.1.2 · Flutter ≥ 3.44.5 · Dart ≥ 3.12.2, < 4.0.0
Preview #

| Hero Carousel | Infinite Gallery |
|---|---|
![]() |
![]() |
Zoom, photo focus, and mobile
| Zoom out · 60% | Zoom in · 180% |
|---|---|
![]() |
![]() |
| Photo focus | Return to gallery |
|---|---|
![]() |
![]() |
Get started #
- English integration guide: installation, runnable example, complete primary API tables, lifecycle, gestures, and troubleshooting.
- 中文接入指南:安装、完整示例、参数、生命周期、手势和常见问题。
- Copyable Dart application.
- Run the full example.
Repository · Issues · MIT License
Usage #
After the first pub.dev release, install with flutter pub add kinetic_gallery.
Before publication, use the local path setup in the integration guide.
import 'package:flutter/material.dart';
import 'package:kinetic_gallery/kinetic_gallery.dart';
Widget carouselExample() => HeroCarousel.builder(
itemCount: 12,
height: 260,
viewportFraction: 0.56,
borderRadius: BorderRadius.circular(20),
itemBuilder: (context, index) => ColoredBox(
color: Colors.primaries[index % Colors.primaries.length],
child: Center(child: Text('Card $index')),
),
);
Widget infiniteExample() => SizedBox(
height: 500,
child: InfiniteCardSpace.builder(
cardSize: const Size(180, 230),
spacing: 24,
heightPattern: const [0.76, 1.22, 0.94, 1.48, 1.06],
itemBuilder: (context, column, row) => ColoredBox(
color: Colors.primaries[(column + row) % Colors.primaries.length],
child: Center(child: Text('$column, $row')),
),
),
);
Place these widgets inside a MaterialApp / Scaffold. Supply your own
images or interactive widgets through itemBuilder; network loading is not
part of the package. Give both layouts a bounded width and the infinite
canvas a bounded height.
Main APIs #
HeroCarousel #
Use HeroCarousel.builder for indexed content or HeroCarousel(children: [...])
for an existing widget list.
| Parameter | Default | Purpose |
|---|---|---|
itemCount, itemBuilder |
Required for .builder |
Number of cards and (context, index) => Widget |
height |
240 |
Carousel height |
viewportFraction |
0.56 |
Active slot width relative to viewport; (0, 1] |
spacing |
8 |
Gap between cards |
activeScale, inactiveScale |
1, 0.78 |
Active and inactive card scale |
activeOpacity, inactiveOpacity |
1, 0.58 |
Active and inactive card opacity |
loop, snap |
false, true |
Looping and snapping |
duration, curve |
380 ms, Curves.easeOutCubic |
Transition timing |
controller |
null |
Programmatic navigation |
itemKeyBuilder |
null |
Stable Key Function(int index) for reorderable data |
borderRadius |
null |
Optional card clipping radius |
onIndexChanged |
null |
Receives the active logical index |
transformBuilder |
null |
Custom visual wrapper using GalleryItemMetrics |
KineticCarouselController #
Create the controller once in State, pass it to one carousel, and dispose it
when the state is disposed. Call navigation methods only after attachment.
final controller = KineticCarouselController(initialIndex: 0);
// Pass controller: controller to HeroCarousel.builder.
// Inside a button callback after the carousel has mounted:
if (controller.isAttached) {
await controller.next();
}
// Inside State.dispose(): controller.dispose();
| Member | Purpose |
|---|---|
next(), previous() |
Animate one card forward or backward |
animateTo(index) |
Animate to a logical index |
jumpTo(index) |
Move immediately |
currentIndex |
Read the active index |
isAttached |
Check whether a carousel is connected |
addListener, removeListener |
Observe index changes |
InfiniteCardSpace #
| Parameter | Default | Purpose |
|---|---|---|
itemBuilder |
Required | (context, column, row) => Widget; coordinates may be negative |
cardSize |
Size(180, 230) |
Base card width and height |
spacing |
24 |
Nonnegative gap between cards |
heightPattern |
[1.0] |
Immutable repeating positive height factors; multiple factors create masonry columns |
minScale, maxScale |
0.6, 1.8 |
Zoom limits |
initialScale |
1.0 |
Initial zoom, within the limits; not a controlled value |
onScaleChanged |
null |
Receives the updated zoom factor |
Only visible cards and a surrounding buffer are mounted. There is no itemCount;
map signed coordinates to your own data. Reset the canvas by changing its widget
key. Pan by dragging, scrolling, or arrow keys; zoom with a pinch, Ctrl+wheel,
or the plus/minus keys while focused.
PhotoPreview #
PhotoPreview opens an image-focused Hero route without coupling that behavior
to InfiniteCardSpace. It uses the nearest Navigator, so each visible tag
must be unique in that navigator. The destination is built separately from the
thumbnail; use it for images and visual content, not for a guaranteed single
state instance of a player, platform view, or GlobalKey widget.
Widget buildPhoto() => ClipRRect(
borderRadius: BorderRadius.circular(20),
child: Image.network(url, fit: BoxFit.cover),
);
PhotoPreview(
tag: 'gallery:$id',
aspectRatio: 0.8,
previewBuilder: (_) => buildPhoto(),
child: buildPhoto(),
)
Use enabled or canOpen to gate taps during a parent gesture. For custom tap
handling, wrap the source in PhotoPreviewHero and call showPhotoPreview with
the same tag and style. PhotoPreviewStyle configures the light backdrop,
target size, transition, drag threshold, and close control. Defaults preserve
the example's 420ms easeOutCubic transition, 80% safe-area size, and vertical
dismissal behavior.
Custom transforms and other exports #
GalleryTransformBuilder receives (context, child, metrics).
GalleryItemMetrics exposes index, signed distance, progress
(max(0, 1 - abs(distance))), and isActive. Return a visual wrapper such as
Transform.rotate; the wrapper does not change the layout slot.
DepthCarousel and MorphGallery remain exported for compatibility.
MorphGalleryController provides focus(index), unfocus(), toggle(index),
focusedIndex, and isAttached. See the additional API reference.
The infinite canvas does not expose focus methods; compose it with
PhotoPreview when cards should open a preview.
What is included #
HeroCarousel: dynamic card widths, snapping, optional looping, controller navigation, custom visual transforms.InfiniteCardSpace: virtualized signed-coordinate layout, periodic masonry heights, four-direction panning, focal pinch zoom (60%–180% by default), desktop zoom input.PhotoPreview: configurable Hero image preview route with tap, keyboard, backdrop, button, system-back, and drag dismissal.
The current example has two entries. MorphGallery, its controller, and DepthCarousel remain exported for compatibility. See historical API notes.
Verification #
See validation records for executed tests and platform limitations, and architecture notes for implementation context. Browser screenshots use real network photos; regression tests use deterministic content. Simulated touch checks are not physical-device certification.





