widgets_extended
High-performance sliver widgets for Flutter: animated tree, sectioned list, and drag-and-drop reorder.
SectionedSliverList— header + items list with sticky headers, expand/collapse, and animated insert/remove.SyncedSliverTree— declarative tree that diffs against a source-of-truth and animates the transitions.SliverReorderableTree— drag-and-drop reorder layer on top of the tree.SliverTree+TreeController— imperative escape hatch.
All widgets are built on the same sliver/TreeController core: viewport-aware lazy layout, ECS-style state storage, animation finalization that doesn't relayout idle rows.
SectionedSliverList
Header + items convenience sliver. Two constructor shapes:
// Declarative SectionInputs.
SectionedSliverList<String, String, Folder, FileItem>(
sections: [
SectionInput(
key: folder.id,
section: folder,
items: [
for (final f in folder.files) ItemInput(key: f.id, item: f),
],
),
// ...
],
headerBuilder: (context, view) => view.watch(
builder: (ctx, v) => ListTile(
title: Text(v.section.name),
trailing: Icon(v.isExpanded ? Icons.expand_more : Icons.chevron_right),
onTap: v.toggle,
),
),
itemBuilder: (context, view) => ListTile(title: Text(view.item.name)),
stickyHeaders: true,
hideEmptySections: false,
initiallyExpanded: true,
)
// groupListsBy-shaped: pass a Map<Section, List<Item>>.
SectionedSliverList<String, String, Folder, FileItem>.grouped(
sections: groupedFolders, // Map<Folder, List<FileItem>>
sectionKeyOf: (folder) => folder.id,
itemKeyOf: (file) => file.id,
headerBuilder: ...,
itemBuilder: ...,
)
Pass a SectionedListController when you need imperative mutations (addItem, removeSection, moveItem, runBatch, ...). Without one, the widget owns its controller internally.
SyncedSliverTree
Use tree: for the simplest entry point when you already have a nested immutable tree:
SyncedSliverTree<String, Folder>(
tree: <SyncedTreeNode<String, Folder>>[
SyncedTreeNode<String, Folder>(
key: root.id,
data: root,
children: <SyncedTreeNode<String, Folder>>[
SyncedTreeNode<String, Folder>(key: child.id, data: child),
],
),
],
itemBuilder: (context, node) => ListTile(
title: Text(node.item.name),
leading: node.hasChildren
? IconButton(
icon: Icon(node.isExpanded ? Icons.expand_more : Icons.chevron_right),
onPressed: node.toggle,
)
: null,
),
)
Use .nodes(...) when your data already exists as roots plus childrenOf(key):
SyncedSliverTree<String, RowData>.nodes(
roots: viewModel.roots,
childrenOf: viewModel.childrenOf,
itemBuilder: (context, node) => buildRow(node),
)
SyncedSliverTree also supports .hierarchy(...), .flat(...), and .snapshot(...) for other source-data shapes.
SliverReorderableTree
Wraps a TreeController with a TreeReorderController to add drag-and-drop reorder, including reparenting between branches:
SliverReorderableTree<String, RowData>(
controller: treeController,
reorderController: reorderController,
nodeBuilder: (context, key, depth, wrap) => wrap(
child: ListTile(title: Text(treeController.getNodeData(key)!.data.label)),
),
indentPerDepth: 24.0,
dropIndicatorColor: Colors.blue,
)
The wrap(child:) callback turns an arbitrary row into a draggable target with the framework-managed drop indicator.
SliverTree + TreeController (imperative)
The lowest layer. Build it directly when you want full control over insert/remove/expand/collapse timing:
final controller = TreeController<String, RowData>(vsync: this);
controller.setRoots([TreeNode(key: "root", data: root)]);
controller.expand(key: "root", animate: true);
CustomScrollView(slivers: [
SliverTree<String, RowData>(
controller: controller,
nodeBuilder: (context, key, depth) => buildRow(controller.getNodeData(key)!.data),
),
])
TreeController exposes addListener (structure changes), addAnimationListener (animation ticks — no relayout), and runBatch(...) (coalesce mutations into one notification).
Libraries
- sectioned_sliver_list/_internal_keys
- Internal sealed wrapper types used to keep section keys, item keys, section payloads, and item payloads in disjoint domains within a single underlying TreeController.
- sectioned_sliver_list/section_input
- Immutable inputs for declarative
SectionedSliverListconstruction. - sectioned_sliver_list/sectioned_list_controller
- Imperative controller for SectionedSliverList.
- sectioned_sliver_list/sectioned_sliver_list
- SectionedSliverList — header + items convenience sliver.
- sectioned_sliver_list/sectioned_sliver_list_widget
- Header + items convenience sliver, built on top of SliverTree.
- sectioned_sliver_list/views
- Views handed to
headerBuilder/itemBuildercallbacks, plus the selective-rebuild helpers (SectionView.watch,ItemView.watch). - sliver_tree/_node_id_registry
- Internal: bidirectional key↔nid mapping with free-list recycling.
- sliver_tree/_node_store
- Internal: structural-component storage for TreeController.
- sliver_tree/_sticky_header_computer
- Internal: sticky-header layout helper for RenderSliverTree.
- sliver_tree/_sync_helpers
- Internal sync-time helpers shared by widgets that drive a TreeController through a TreeSyncController. Not exported from the package barrel.
- sliver_tree/_visible_order_buffer
- Internal: flattened visible-order buffer for a TreeController.
- sliver_tree/render_sliver_tree
- Render object for SliverTree that handles sliver layout and painting.
- sliver_tree/sliver_reorderable_tree
- Declarative wrapper around SliverTree that adds drag-and-drop reorder over a TreeReorderController.
- sliver_tree/sliver_tree
- sliver_tree/sliver_tree_element
- Element for SliverTree that manages child element lifecycle.
- sliver_tree/sliver_tree_widget
- Widget for displaying a tree structure as a sliver.
- sliver_tree/synced_sliver_tree
- A declarative sliver tree with data-first input modes.
- sliver_tree/synced_tree_node
- Immutable nested tree node for SyncedSliverTree.
- sliver_tree/tree_controller
- Controller that manages tree state, visibility, and animations.
- sliver_tree/tree_node_builder
- A widget that rebuilds only when a specific node's state changes.
- sliver_tree/tree_reorder_controller
- Orchestrates drag-and-drop reorder over a TreeController-backed SliverTree: gesture lifecycle, drop-target resolution, autoscroll near viewport edges, and FLIP slide animation on commit.
- sliver_tree/tree_sync_controller
- A diffing/syncing layer on top of TreeController.
- sliver_tree/types
- Core types for the sliver tree system.
- widgets_extended