tree_view_with_drag_and_drop 1.0.3 copy "tree_view_with_drag_and_drop: ^1.0.3" to clipboard
tree_view_with_drag_and_drop: ^1.0.3 copied to clipboard

A customizable Flutter tree view widget with drag-and-drop support for reordering nodes. Supports generic data types and provides extensive customization options.

Flutter Tree Drag Drop #

A customizable Flutter tree view widget with intuitive drag-and-drop support for reordering nodes. Perfect for file explorers, organizational charts, menu systems, and any hierarchical data visualization.

pub package License: MIT

Features #

Generic Data Support - Use any data type with TreeNode<T>
🎯 Drag & Drop - Intuitive reordering with visual feedback
🎨 Highly Customizable - Control appearance and behavior
📂 Expand/Collapse - Show or hide child nodes
🎮 Controller API - Programmatically control the tree
Performance - Efficiently handles large trees
🔒 Circular Dependency Prevention - Built-in safety checks

Installation #

Add this to your package's pubspec.yaml file:

dependencies:
  tree_view_with_drag_and_drop: ^1.0.3

Then run:

flutter pub get

Quick Start #

Basic Usage #

import 'package:flutter/material.dart';
import 'package:tree_view_with_drag_and_drop/tree_view_with_drag_and_drop.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  late List<TreeNode<String>> treeData;

  @override
  void initState() {
    super.initState();
    treeData = [
      TreeNode<String>(
        id: '1',
        data: 'Documents',
        children: [
          TreeNode<String>(id: '1.1', data: 'Work'),
          TreeNode<String>(id: '1.2', data: 'Personal'),
        ],
      ),
      TreeNode<String>(
        id: '2',
        data: 'Photos',
        children: [
          TreeNode<String>(id: '2.1', data: 'Vacation'),
          TreeNode<String>(id: '2.2', data: 'Family'),
        ],
      ),
    ];
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Tree View Demo')),
        body: TreeView<String>(
          nodes: treeData,
          itemBuilder: (context, node, isExpanded) {
            return ListTile(
              leading: Icon(
                node.hasChildren ? Icons.folder : Icons.insert_drive_file,
              ),
              title: Text(node.data),
              trailing: node.hasChildren
                  ? Icon(isExpanded ? Icons.expand_more : Icons.chevron_right)
                  : null,
              onTap: node.hasChildren
                  ? () {
                      setState(() {
                        node.isExpanded = !node.isExpanded;
                      });
                    }
                  : null,
            );
          },
          onReorder: (draggedNode, targetNode, position) {
            print('Moved ${draggedNode.data} to $position of ${targetNode.data}');
            setState(() {
              // Tree is automatically updated
            });
          },
        ),
      ),
    );
  }
}

Advanced Usage #

Custom Data Types #

Use any data type with the generic TreeNode<T>:

class FileItem {
  final String name;
  final IconData icon;
  final int size;

  FileItem(this.name, this.icon, this.size);
}

final treeData = [
  TreeNode<FileItem>(
    id: '1',
    data: FileItem('Documents', Icons.folder, 0),
    children: [
      TreeNode<FileItem>(
        id: '1.1',
        data: FileItem('report.pdf', Icons.picture_as_pdf, 1024),
      ),
    ],
  ),
];

TreeView<FileItem>(
  nodes: treeData,
  itemBuilder: (context, node, isExpanded) {
    return ListTile(
      leading: Icon(node.data.icon),
      title: Text(node.data.name),
      subtitle: node.data.size > 0 
          ? Text('${node.data.size} bytes') 
          : null,
    );
  },
)

Customization #

Custom Appearance

TreeView<String>(
  nodes: treeData,
  config: TreeItemConfig(
    indentPerLevel: 32.0,
    dropIndicatorColor: Colors.green,
    dropIndicatorThickness: 3.0,
    highlightColor: Colors.green.shade50,
    highlightBorderColor: Colors.green,
    borderRadius: 12.0,
    dragOpacity: 0.5,
  ),
  itemBuilder: (context, node, isExpanded) {
    // Your custom item widget
  },
)

Custom Drag Feedback

TreeView<String>(
  nodes: treeData,
  itemBuilder: (context, node, isExpanded) {
    // Normal item
  },
  feedbackBuilder: (context, node) {
    return Container(
      padding: EdgeInsets.all(12),
      decoration: BoxDecoration(
        color: Colors.purple.shade100,
        borderRadius: BorderRadius.circular(8),
        boxShadow: [
          BoxShadow(
            color: Colors.black26,
            blurRadius: 8,
            offset: Offset(0, 4),
          ),
        ],
      ),
      child: Row(
        mainAxisSize: MainAxisSize.min,
        children: [
          Icon(Icons.drag_indicator, color: Colors.purple),
          SizedBox(width: 8),
          Text(node.data, style: TextStyle(fontWeight: FontWeight.bold)),
        ],
      ),
    );
  },
)

Using the Controller #

class MyWidget extends StatefulWidget {
  @override
  _MyWidgetState createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  final TreeViewController<String> controller = TreeViewController<String>();

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Row(
          children: [
            ElevatedButton(
              onPressed: () => controller.expandAll(),
              child: Text('Expand All'),
            ),
            ElevatedButton(
              onPressed: () => controller.collapseAll(),
              child: Text('Collapse All'),
            ),
          ],
        ),
        Expanded(
          child: TreeView<String>(
            controller: controller,
            nodes: treeData,
            itemBuilder: (context, node, isExpanded) {
              // Your item widget
            },
          ),
        ),
      ],
    );
  }
}

Callbacks #

TreeView<String>(
  nodes: treeData,
  itemBuilder: (context, node, isExpanded) {
    // Item widget
  },
  onReorder: (draggedNode, targetNode, position) {
    print('Node ${draggedNode.id} moved ${position} ${targetNode.id}');
    // Update your data model if needed
  },
  onNodeExpanded: (node, isExpanded) {
    print('Node ${node.id} expanded: $isExpanded');
    // Save expansion state, analytics, etc.
  },
)

Disable Drag & Drop #

TreeView<String>(
  nodes: treeData,
  enableDragAndDrop: false,
  itemBuilder: (context, node, isExpanded) {
    // Read-only tree view
  },
)

API Reference #

TreeNode #

Property Type Description
id String Unique identifier
data T Custom data
children List<TreeNode<T>> Child nodes
isExpanded bool Expansion state
metadata Map<String, dynamic>? Additional data

TreeView #

Property Type Description
nodes List<TreeNode<T>> Root nodes
itemBuilder Widget Function(...) Item widget builder
feedbackBuilder Widget Function(...)? Drag feedback builder
config TreeItemConfig Visual configuration
enableDragAndDrop bool Enable/disable drag & drop
onReorder Function(...)? Reorder callback
onNodeExpanded Function(...)? Expansion callback
controller TreeViewController<T>? Controller instance

TreeItemConfig #

Property Type Default Description
indentPerLevel double 24.0 Indent per level
dropIndicatorColor Color Colors.blue Drop line color
dropIndicatorThickness double 2.0 Drop line thickness
highlightColor Color Color(0xFFE3F2FD) Highlight color
highlightBorderColor Color Colors.blue Highlight border
borderRadius double 8.0 Item border radius
dragOpacity double 0.3 Dragging opacity

TreeViewController #

Method Description
expandAll() Expand all nodes
collapseAll() Collapse all nodes
treeData Get current tree data
updateTreeData(List<TreeNode<T>>) Update tree data

Examples #

Check out the example directory for complete working examples:

  • Simple Tree - Basic file explorer
  • Custom Data - Using custom objects
  • Styled Tree - Custom styling and themes
  • Controlled Tree - Using the controller API

Tips & Best Practices #

  1. Unique IDs: Always use unique IDs for each node
  2. Performance: For large trees, consider lazy loading children
  3. State Management: Integrate with your state management solution
  4. Persistence: Save tree state (expansion, order) if needed
  5. Validation: Validate drops in onReorder callback

Contributing #

Contributions are welcome! Please feel free to submit a Pull Request.

License #

This project is licensed under the MIT License - see the LICENSE file for details.

Support #

If you find this package useful, please give it a ⭐️ on GitHub!

For issues and feature requests, visit the issue tracker.

1
likes
140
points
145
downloads

Publisher

unverified uploader

Weekly Downloads

A customizable Flutter tree view widget with drag-and-drop support for reordering nodes. Supports generic data types and provides extensive customization options.

Repository (GitHub)
View/report issues

Topics

#tree-view #drag-and-drop #hierarchical-data #ui #widget

Documentation

API reference

License

MIT (license)

Dependencies

cupertino_icons, flutter

More

Packages that depend on tree_view_with_drag_and_drop