keyed_indexed_stack 0.1.0
keyed_indexed_stack: ^0.1.0 copied to clipboard
A lazy-loading replacement for IndexedStack with generic keys, keep-alive, preheat, and lifecycle callbacks.
keyed_indexed_stack #
A lazy-loading replacement for Flutter's IndexedStack.
Unlike IndexedStack which eagerly builds all children at once, this widget
only builds children that are active, kept alive, or preheated. Children are
constructed when first needed, may remain mounted while inactive, and may be
disposed when no longer needed.
Features #
- Lazy building — children are built only when first needed
- Generic keys — use enums, strings, or any type with proper
==andhashCode - Keep-alive — specify keys that should stay built when inactive
- Preheat — build children offstage before they become visible
- Lifecycle callbacks —
onSwitch,onChildBuilt,onChildDisposed - Controller — imperative API for preheat, dispose, keep-alive, and switching
Behavior Notes #
onSwitchfires after theindexchange has been applied, not before.onChildBuiltfires whenever a key is added to the tree. If a child is disposed and later rebuilt, the callback fires again.controller.switchTo()only requests a switch throughonIndexRequested. The parent must updateindexfor the visible child to change.controller.disposeKeys()only releases controller-managed retention for those keys. DeclarativekeepAlive/preheatstill apply.controller.forceDisposeKeys()is the explicit override. It can remove declaratively retained children, but it does not remove the current active child.
Usage #
enum Tab { home, search, profile }
class MyApp extends StatefulWidget {
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
Tab _currentTab = Tab.home;
@override
Widget build(BuildContext context) {
return LazyIndexedStack<Tab>(
index: _currentTab,
keepAlive: {Tab.home},
preheat: {Tab.search},
builder: (context, key) => MyPage(tab: key),
);
}
}
With controller #
final controller = LazyIndexedStackController<Tab>();
LazyIndexedStack<Tab>(
index: _currentTab,
controller: controller,
onIndexRequested: (key) => setState(() => _currentTab = key),
builder: (context, key) => MyPage(tab: key),
);
// Imperative commands:
controller.preheat({Tab.search}); // Build search offstage
controller.addKeepAlive({Tab.home}); // Keep home alive forever
controller.disposeKeys({Tab.search}); // Release controller retention
controller.forceDisposeKeys({Tab.search}); // Force-remove search from tree
controller.switchTo(Tab.profile); // Switch to profile
Lifecycle callbacks #
LazyIndexedStack<Tab>(
index: _currentTab,
onSwitch: (from, to) => print('Switch: $from -> $to'),
onChildBuilt: (key) => print('Built: $key'),
onChildDisposed: (key) => print('Disposed: $key'),
builder: (context, key) => MyPage(tab: key),
);
API #
LazyIndexedStack<T> #
| Parameter | Type | Description |
|---|---|---|
index |
T (required) |
Currently visible key |
builder |
Widget Function(BuildContext, T) (required) |
Widget builder per key |
controller |
LazyIndexedStackController<T>? |
Imperative control |
keepAlive |
Set<T> |
Keys that stay built when inactive |
preheat |
Set<T> |
Keys to build offstage before visiting |
onSwitch |
void Function(T from, T to)? |
Called after the active index changes |
onChildBuilt |
void Function(T)? |
Called whenever a child is added to the tree |
onChildDisposed |
void Function(T)? |
Called when child is removed |
onIndexRequested |
void Function(T)? |
Called by controller.switchTo() |
Stack pass-through: alignment, textDirection, clipBehavior, sizing.
LazyIndexedStackController<T> #
| Method | Description |
|---|---|
preheat(Set<T>) |
Build children offstage |
disposeKeys(Set<T>) |
Release controller-managed retention and reconcile built children |
forceDisposeKeys(Set<T>) |
Force-remove built children even if declaratively retained |
addKeepAlive(Set<T>) |
Add to keep-alive set |
removeKeepAlive(Set<T>) |
Remove from keep-alive set |
switchTo(T) |
Request an active key change via onIndexRequested |
| Property | Description |
|---|---|
builtKeys |
Set of currently built keys |
currentKey |
Currently active key |
isBuilt(T) |
Whether a key is built |
License #
MIT