drag_split_layout 0.1.1 copy "drag_split_layout: ^0.1.1" to clipboard
drag_split_layout: ^0.1.1 copied to clipboard

A Flutter package for creating resizable split-pane layouts with drag-and-drop support. Easily rearrange, split, and replace panes with intuitive gestures and visual drop previews.

Drag Split Layout #

pub package style: very good analysis License: MIT

A Flutter package for creating resizable split-pane layouts with drag-and-drop support. Build IDE-like interfaces where users can rearrange, split, and replace panes with intuitive gestures and visual drop previews.

Features #

  • Drag and Drop Rearrangement - Drag panes to rearrange them within the layout
  • Split Zones - Drop on edges (left, right, top, bottom) to split panes
  • Replace Zones - Drop in center to replace existing panes
  • Visual Drop Preview - Blue preview for split operations, green for replace
  • Resizable Panes - Drag dividers to resize panes (powered by multi_split_view)
  • Edit Mode Toggle - Enable/disable drag-and-drop functionality
  • Mobile Support - Long-press dragging on touch devices
  • Customizable Styling - Configure colors, borders, animations, and more

Installation #

Add drag_split_layout to your pubspec.yaml:

dependencies:
  drag_split_layout: ^0.1.0

Then run:

flutter pub get

Quick Start #

Basic Usage #

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

class MyLayoutEditor extends StatefulWidget {
  @override
  State<MyLayoutEditor> createState() => _MyLayoutEditorState();
}

class _MyLayoutEditorState extends State<MyLayoutEditor> {
  late SplitLayoutController _controller;

  @override
  void initState() {
    super.initState();
    _controller = SplitLayoutController(
      rootNode: SplitNode.branch(
        id: 'root',
        axis: SplitAxis.horizontal,
        children: [
          SplitNode.leaf(
            id: 'panel_1',
            widgetBuilder: (_) => Container(
              color: Colors.blue[100],
              child: const Center(child: Text('Panel 1')),
            ),
          ),
          SplitNode.leaf(
            id: 'panel_2',
            widgetBuilder: (_) => Container(
              color: Colors.green[100],
              child: const Center(child: Text('Panel 2')),
            ),
          ),
        ],
      ),
    );
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return EditableMultiSplitView(
      controller: _controller,
    );
  }
}

Simple Layout (Without Manual Tree Construction) #

SimpleEditableLayout(
  initialAxis: SplitAxis.horizontal,
  editMode: true,
  children: [
    Container(color: Colors.red[100], child: Text('Panel 1')),
    Container(color: Colors.blue[100], child: Text('Panel 2')),
    Container(color: Colors.green[100], child: Text('Panel 3')),
  ],
)

Core Concepts #

SplitNode #

The layout is represented as a tree of SplitNode objects:

  • Leaf Node - Contains a widget (the actual content)
  • Branch Node - Contains child nodes arranged along an axis
// Leaf node with content
SplitNode.leaf(
  id: 'editor',
  flex: 2.0, // Takes 2x space relative to siblings
  widgetBuilder: (context) => MyEditorWidget(),
)

// Branch node with children
SplitNode.branch(
  id: 'main',
  axis: SplitAxis.horizontal, // or SplitAxis.vertical
  children: [leafNode1, leafNode2],
)

SplitLayoutController #

Manages the layout tree and edit mode:

final controller = SplitLayoutController(rootNode: myRootNode);

// Toggle edit mode
controller.editMode = true; // Enable drag-and-drop
controller.editMode = false; // Disable drag-and-drop

// Update the layout
controller.updateRootNode(newRootNode);

// Find nodes
final path = controller.findPathById('panel_1');
final node = controller.getNodeAtPath([0, 1]);

// Listen to changes
controller.addListener(() {
  print('Layout changed!');
});

Drop Zones #

When dragging a pane over another, the drop zone is determined by pointer position:

Zone Position Action
Left Left 20% of pane Split horizontally, insert left
Right Right 20% of pane Split horizontally, insert right
Top Top 20% of pane Split vertically, insert above
Bottom Bottom 20% of pane Split vertically, insert below
Center Middle 60% of pane Replace the target pane

Configuration #

EditableMultiSplitViewConfig #

EditableMultiSplitView(
  controller: _controller,
  config: EditableMultiSplitViewConfig(
    dividerThickness: 8.0,
    antiAliasingWorkaround: true,
    paneConfig: DraggablePaneConfig(
      dragFeedbackOpacity: 0.7,
      dragFeedbackScale: 0.9,
      useLongPressOnMobile: true,
      longPressDuration: Duration(milliseconds: 300),
      previewStyle: DropPreviewStyle(
        splitColor: Color(0x4D2196F3), // Blue for split
        replaceColor: Color(0x4D4CAF50), // Green for replace
        borderWidth: 2.0,
        borderRadius: 4.0,
        animationDuration: Duration(milliseconds: 150),
      ),
    ),
  ),
)

Custom Drop Handling #

EditableMultiSplitView(
  controller: _controller,
  onNodeDropped: (draggedItem, preview, targetNode) {
    // Return a custom node, or null to cancel the drop
    if (preview.zone == DropZone.center) {
      // Custom handling for replace operations
      return SplitNode.leaf(
        id: 'custom_${DateTime.now().millisecondsSinceEpoch}',
        widgetBuilder: (_) => MyCustomWidget(),
      );
    }
    // Return null to use default behavior
    return null;
  },
)

Advanced Usage #

External Drag Sources #

Accept drops from external drag sources (like a component palette):

class PaletteItem {
  final String type;
  final String title;
  final IconData icon;
}

// In your palette widget
Draggable<PaletteItem>(
  data: PaletteItem(type: 'editor', title: 'Code Editor', icon: Icons.code),
  dragAnchorStrategy: pointerDragAnchorStrategy,
  feedback: Material(
    child: Container(
      padding: EdgeInsets.all(12),
      child: Text('Code Editor'),
    ),
  ),
  child: ListTile(title: Text('Code Editor')),
)

// Handle the drop in your panel widget using DragTarget<PaletteItem>

Nested Layouts #

Create complex nested layouts:

SplitNode.branch(
  id: 'root',
  axis: SplitAxis.horizontal,
  children: [
    // Left sidebar
    SplitNode.leaf(id: 'sidebar', flex: 0.5, widgetBuilder: ...),
    // Main area with nested vertical split
    SplitNode.branch(
      id: 'main',
      axis: SplitAxis.vertical,
      flex: 2.0,
      children: [
        SplitNode.leaf(id: 'editor', flex: 2.0, widgetBuilder: ...),
        SplitNode.leaf(id: 'terminal', flex: 1.0, widgetBuilder: ...),
      ],
    ),
    // Right panel
    SplitNode.leaf(id: 'preview', flex: 1.0, widgetBuilder: ...),
  ],
)

Programmatic Layout Manipulation #

// Get current root node
final root = controller.rootNode;

// Replace a node at path
final newRoot = root.replaceAtPath([0, 1], newNode);
controller.updateRootNode(newRoot);

// Insert a node
final withInserted = root.insertAtPath([0], 1, newNode);
controller.updateRootNode(withInserted);

// Remove a node
final withRemoved = root.removeAtPath([0, 2]);
controller.updateRootNode(withRemoved);

// Wrap a node in a new branch (split it)
final wrapped = root.wrapInBranch(
  [0], // path to node
  SplitAxis.vertical, // new split axis
  newSiblingNode, // node to add
  true, // insert before (true) or after (false)
);
controller.updateRootNode(wrapped);

API Reference #

Main Classes #

Class Description
SplitNode Represents a node in the layout tree
SplitLayoutController Manages layout state and edit mode
EditableMultiSplitView Main widget for rendering the layout
SimpleEditableLayout Simplified widget for basic layouts
DraggableSplitPane Wrapper that makes panes draggable
DropTargetPane Drop target without being draggable

Models #

Class Description
DragItemModel Data transferred during drag operations
DropPreviewModel Information about the current drop preview
DropZone Enum for drop zones (left, right, top, bottom, center)
DropAction Enum for drop actions (split, replace)
SplitAxis Enum for split direction (horizontal, vertical)

Configuration Classes #

Class Description
EditableMultiSplitViewConfig Configuration for the main widget
DraggablePaneConfig Configuration for draggable behavior
DropPreviewStyle Styling for drop preview overlays

Example #

Check out the example directory for a complete demo application featuring:

  • Resizable split panes
  • Drag-and-drop rearrangement
  • Component palette for adding new panels
  • Edit mode toggle
  • Multiple panel types

Run the example:

cd example
flutter run

Requirements #

  • Flutter SDK: ^3.24.0
  • Dart SDK: ^3.5.0

Dependencies #

Contributing #

Contributions are welcome! Please read our contributing guidelines before submitting a pull request.

License #

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

2
likes
155
points
33
downloads

Publisher

verified publisherlkrjangid.tech

Weekly Downloads

A Flutter package for creating resizable split-pane layouts with drag-and-drop support. Easily rearrange, split, and replace panes with intuitive gestures and visual drop previews.

Repository (GitHub)
View/report issues

Topics

#layout #drag-and-drop #split-view #resizable #ui

Documentation

API reference

License

MIT (license)

Dependencies

flutter, multi_split_view

More

Packages that depend on drag_split_layout