interactive_tree_view 0.10.0 copy "interactive_tree_view: ^0.10.0" to clipboard
interactive_tree_view: ^0.10.0 copied to clipboard

A flutter library for creating interactive treeviews and managing tree-like structures.

Interactive tree view #

A flutter library that aims to make it easier to deal with tree structures in both logic and UI.

Example #

Gif

final uuid = Uuid();

class ExampleTreeView extends StatefulWidget {
  const ExampleTreeView({super.key, required this.title});
  final String title;

  @override
  State<ExampleTreeView> createState() => _ExampleTreeViewState();
}

class _ExampleTreeViewState extends State<ExampleTreeView> {
  final controller = TreeController(
    initialNodes: [
      TreeNode(
        uuid.v1(),
        'node 1',
        children: [
          TreeNode(uuid.v1(), 'node 3'),
          TreeNode(uuid.v1(), 'node 4'),
        ],
      ),
      TreeNode(uuid.v1(), 'node 2', children: [TreeNode(uuid.v1(), 'node 5')]),
    ],
    onAttached: (node, parent) {
      print('Attached node ${node.identifier}');
    },
    onMoved: (node, index, oldParent, newParent) {
      print('Moved node ${node.identifier} to index $index');
    },
    onRemoved: (node, parent) {
      print('Removed node ${node.identifier}');
    },
  );

  void _onAdd(TreeNode parent) async {
    // Show dialog to add a new node
  }

  @override
  Widget build(BuildContext context) {
    return TreeView(
      controller: controller,
      nodeBuilder: (context, node) => Container(
        decoration: BoxDecoration(
          color: Theme.of(context).colorScheme.primaryContainer,
          borderRadius: BorderRadius.circular(4),
        ),
        height: 48,
        width: double.infinity,
        padding: const EdgeInsets.all(8),
        child: Row(
          children: [
            Text(node.data!.toString()),
            const Spacer(),
            IconButton(
              onPressed: () => _onAdd(node),
              icon: const Icon(Icons.add),
            ),
            IconButton(
              onPressed: () => controller.remove(node),
              icon: const Icon(Icons.remove),
            ),
            if (node.isParent)
              IconButton(
                onPressed: node.toggle,
                icon: Icon(
                  node.expanded ? Icons.arrow_drop_up : Icons.arrow_drop_down,
                ),
              ),
          ],
        ),
      ),
    );
  }
}

Features #

  • Drag-and-drop nodes
  • Expand / collapse animations
  • Controller- and node-based updates
  • Node lookup and manipulation via unique identifiers
  • Event listeners for node changes through TreeController

Key terms #

  • Node — an element in the tree.
    • Parent node — the node directly above a given node.
    • Sibling node — a node sharing the same parent.
    • Child node — a node directly under a given node.
    • Root node — a node without a parent (depth 0).
  • Depth — number of steps from the node to a root node (root = 0).
  • Indicator — UI element shown while dragging that indicates the drop position.

TreeController #

Manages nodes, their positions, and notifies listeners when changes occur.

Important: movement and relationship methods require the node to be attached to the controller.

How nodes become attached #

  • Provided via initialNodes in the controller constructor.
  • Added with controller.attachRoot(...).
  • Added with node.attachChild(...).
  • Added with node.attachSibling(...).

Constructor example #

final controller = TreeController(
  initialNodes: [...],
  onAttached: (node, index, parent) {
    // called when a node is attached
    // node: attached node
    // index: position among siblings
    // parent: parent node or null if root
  },
  onMoved: (node, index, oldParent, newParent) {
    // called when an attached node is moved, directly or indirectly
  },
  onRemoved: (node, index, parent) {
    // called when a node is removed/detached
  },
  onChanged: (){
    // called when the tree configuration changes
    // this calls only once per change
  }
);

methods #

controller.getByIdentifier(id);
controller.addRoot(node);
controller.remove(node);
controller.move(node, index, newParent: parentNode);
controller.swap(node1, node2);
controller.traverse(action);
controller.collapseAll();
controller.expandAll();

For more details, see: TreeController api reference


Tree nodes (TreeNode) #

A TreeNode is an individual item. Construction alone does not attach it to a controller — attach it before using movement-related APIs.

Constructor example #

final node = TreeNode<String>(
  uuid.v1(),                 // unique identifier
  'Node data',               // payload
  children: [nodeA, nodeB], // optional children
  draggable: true,           // defaults to true
  expanded: true,            // defaults to true
);

Properties #

node.identifier;     // unique id
node.data;           // payload
node.children;       // list of children
node.parent;         // parent node (null for root)
node.siblings;       // sibling list (attached nodes only)
node.isParent;       // true when this node has children
node.isNotParent;    // inverse of isParent
node.depth;          // root depth = 0
node.expanded;       // whether this node is expanded
node.isBeingDragged; // true when the node is currently dragged

Methods #

node.attachChild(childNode);
node.attachSibling(siblingNode);
node.moveUp();
node.moveDown();
node.move(index, parent: parentNode);
//swap swaps the location of two nodes in the tree
node.swap(otherNode);
//replaceWith replaces a node with a new node instance
node.replaceWith(notAttachedNode);
node.expand();
node.collapse();
node.toggle();
node.traverse(action)

For more details, see: TreeNode api reference


TreeView widget #

Displays a tree from a TreeController.

Constructor #

TreeView(
  //Controller to build from.
  controller: controller,
  //Builder that is used for each node.
  nodeBuilder: (context, node) {},
  //UI element shown while dragging that indicates the drop position.
  indicator: const DefaultIndicator(height: 15),
  //A builder to use if you want an indicator that depends on the node that is used as reference for its placement. 
  indicatorBuilder: (context, referenceNode, placement) {},
  indent: 8.0, // horizontal indent per depth (default 8.0).
  spacing: 8.0, // vertical spacing between nodes
  //The duration of the animation.
  animationDuration: const Duration(milliseconds: 100),
);

Nodes in this tree can be dragged by the user to be placed somewhere else in the tree. To make a node a child of another node, drag it to the right side of that node until the indicator becomes indented.

StaticTreeView widget #

Displays a tree from a list of TreeNodes. Very similar to TreeView, but does not allow the user to modify the tree through the ui. Takes a list of TreeNode instead of a TreeController. #

Misc. #

There are no built-in selection or highlighting utilities because this is quite trivial to implement. See the example in the repository for a suggested implementation.

This widget was not built or tested for performance, until now i have not encountered any performance issues using the package.Performance could degrade when using very deep trees but since trees are not a very convenient way to display large datasets this is not an expected usecase.


0
likes
160
points
33
downloads

Publisher

verified publisherdart.share-a-bite.nl

Weekly Downloads

A flutter library for creating interactive treeviews and managing tree-like structures.

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

flutter

More

Packages that depend on interactive_tree_view