Boundless Stack is a Flutter package that provides infinite scrolling and scaling capabilities in a two-dimensional space. This document provides comprehensive API documentation for all classes and methods.
The main widget that creates an infinite scrollable stack.
class BoundlessStack extends StatefulWidget {
const BoundlessStack({
Key? key,
this.primary,
this.mainAxis = Axis.vertical,
this.verticalDetails = const ScrollableDetails.vertical(),
this.horizontalDetails = const ScrollableDetails.horizontal(),
required this.delegate,
this.cacheExtent,
this.diagonalDragBehavior = DiagonalDragBehavior.free,
this.dragStartBehavior = DragStartBehavior.start,
this.keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual,
this.clipBehavior = Clip.hardEdge,
required this.scaleFactor,
this.backgroundBuilder,
this.foregroundBuilder,
});
}- delegate (
BoundlessStackDelegate): Provides children for the stack - scaleFactor (
ValueNotifier<double>): Controls zoom level - backgroundBuilder (
TwoDimensionalViewportBuilder?): Custom background renderer - foregroundBuilder (
TwoDimensionalViewportBuilder?): Custom foreground renderer - cacheExtent (
double?): Number of items to pre-render around viewport - diagonalDragBehavior (
DiagonalDragBehavior): Controls diagonal scrolling behavior - verticalDetails (
ScrollableDetails): Vertical scrolling configuration - horizontalDetails (
ScrollableDetails): Horizontal scrolling configuration
- overrideScrollBehavior(): Temporarily disables scrolling (used during gestures)
- restoreScrollBehavior(): Restores original scroll behavior
Represents a positioned widget within the boundless stack.
class StackPosition extends StatefulWidget {
const StackPosition({
Key? key,
required this.scaleFactor,
this.moveable,
this.resizable,
required this.notifier,
required this.builder,
this.child,
});
}- scaleFactor (
ValueNotifier<double>): Current scale factor - moveable (
StackMove?): Movement configuration - resizable (
StackResize?): Resize configuration - notifier (
ValueNotifier<StackPositionData>): Position data notifier - builder (
StackPositionWidgetBuilder): Widget builder function - child (
Widget?): Optional child widget
Data class that holds position and size information for stack items.
@MappableClass()
class StackPositionData {
const StackPositionData({
required this.id,
required this.layer,
required this.offset,
this.keepAlive = false,
this.width,
this.preferredWidth,
this.height,
this.preferredHeight,
});
}- id (
String): Unique identifier - layer (
int): Z-index layer - offset (
Offset): Position in 2D space - width/height (
double?): Fixed dimensions - preferredWidth/preferredHeight (
double?): Preferred dimensions - keepAlive (
bool): Whether to keep widget alive when off-screen
- calculateScaledOffset(double scaleFactor): Calculates the offset adjusted for scale
- copyWith(): Creates a copy with optional new values
Handles zoom and pan gestures for the boundless stack.
class ZoomStackGestureDetector extends StatefulWidget {
const ZoomStackGestureDetector({
Key? key,
required this.scaleFactor,
this.enableMoveByTouch = false,
this.enableMoveByMouse = false,
this.supportedDevices = const {...PointerDeviceKind.values},
required this.stack,
this.onScaleFactorChanged,
this.onScaleStart,
this.onScaleEnd,
});
}- scaleFactor (
ValueNotifier<double>): Scale factor notifier - enableMoveByTouch (
bool): Whether to enable movement by touch - enableMoveByMouse (
bool): Whether to enable movement by mouse - supportedDevices (
Set<PointerDeviceKind>): Supported input devices - stack (
BoundlessStack Function(...)): Stack builder function - onScaleFactorChanged (
Function(double)?): Scale change callback - onScaleStart/onScaleEnd (
VoidCallback?): Scale event callbacks
Abstract base class for providing children to the boundless stack.
abstract class BoundlessStackDelegate extends TwoDimensionalChildDelegate {
BoundlessStackDelegate({
required this.childrenBuilder,
this.layerSorted = false,
});
}- childrenBuilder (
List<StackPosition> Function(Rect viewport)): Function that builds children - layerSorted (
bool): Whether to sort children by layer
Concrete implementation that provides a static list of children.
class BoundlessStackListDelegate extends BoundlessStackDelegate {
factory BoundlessStackListDelegate({
bool layerSorted = false,
required List<StackPosition> children,
});
}Configuration for item movement behavior.
class StackMove {
const StackMove({this.snap});
final StackSnap? snap;
}Defines snap-to-grid behavior.
class StackSnap {
const StackSnap({
required this.heightSnap,
required this.widthSnap,
});
factory StackSnap.square({required double snap});
}Configuration for item resizing behavior.
class StackResize {
const StackResize({
required this.width,
required this.preferredWidth,
required this.height,
required this.preferredHeight,
this.preferredOverFixedSize = false,
this.thumb,
this.onSizeChanged,
});
}- width/height (
double?): Fixed dimensions - preferredWidth/preferredHeight (
double?): Preferred dimensions - preferredOverFixedSize (
bool): Whether to prioritize preferred size - thumb (
Widget?): Resize handle widget - onSizeChanged (
ValueChanged<Size>?): Size change callback
Creates a grid background for the boundless stack.
TwoDimensionalViewportBuilder gridBackgroundBuilder({
required double gridThickness,
required double gridWidth,
required double gridHeight,
required Color gridColor,
required ValueNotifier<double> scaleFactor,
});- gridThickness (
double): Thickness of grid lines - gridWidth/gridHeight (
double): Size of grid cells - gridColor (
Color): Color of grid lines - scaleFactor (
ValueNotifier<double>): Current scale factor
typedef StackPositionWidgetBuilder = Widget Function(
BuildContext context,
ValueNotifier<StackPositionData> notifier,
Widget? child,
);
typedef TwoDimensionalViewportBuilder = Widget Function(
BuildContext context,
ViewportOffset horizontalOffset,
ViewportOffset verticalOffset,
);BoundlessStack(
scaleFactor: scaleNotifier,
delegate: BoundlessStackListDelegate(
children: stackPositions,
),
horizontalDetails: ScrollableDetails.horizontal(),
verticalDetails: ScrollableDetails.vertical(),
)ZoomStackGestureDetector(
scaleFactor: scaleNotifier,
stack: (key, scaleFactor) => BoundlessStack(
key: key,
scaleFactor: scaleFactor,
delegate: BoundlessStackListDelegate(
children: stackPositions,
),
),
)StackPosition(
moveable: StackMove(
snap: StackSnap.square(snap: 50.0),
),
// ... other properties
)StackPosition(
resizable: StackResize(
width: 200,
height: 200,
preferredWidth: 200,
preferredHeight: 200,
thumb: Container(
width: 20,
height: 20,
color: Colors.blue,
),
),
// ... other properties
)BoundlessStack(
backgroundBuilder: gridBackgroundBuilder(
gridWidth: 100,
gridHeight: 100,
gridColor: Colors.grey,
gridThickness: 1.0,
scaleFactor: scaleNotifier,
),
// ... other properties
)BoundlessStackListDelegate(
layerSorted: true,
children: [
StackPosition(
notifier: ValueNotifier(StackPositionData(
id: 'background',
layer: 0,
offset: Offset.zero,
)),
// ... other properties
),
StackPosition(
notifier: ValueNotifier(StackPositionData(
id: 'foreground',
layer: 1,
offset: Offset(100, 100),
)),
// ... other properties
),
],
)