Question #345MediumWidgets & UI

How do you implement a draggable widget in flutter?

#widget#draggable#gestures

Answer

Overview

Flutter provides two primary ways to implement draggable widgets: the

text
Draggable
/
text
DragTarget
system for drag-and-drop, and
text
GestureDetector
for free-form drag gestures.


1. Draggable + DragTarget

Use this for drag-and-drop between specific targets.

dart
class DragDropExample extends StatefulWidget {
  
  _DragDropExampleState createState() => _DragDropExampleState();
}

class _DragDropExampleState extends State<DragDropExample> {
  Color _targetColor = Colors.grey[300]!;

  
  Widget build(BuildContext context) {
    return Column(
      children: [
        // The draggable item
        Draggable<Color>(
          data: Colors.blue, // Data to pass to the target
          feedback: Container(
            width: 80, height: 80,
            decoration: BoxDecoration(
              color: Colors.blue.withOpacity(0.7),
              shape: BoxShape.circle,
            ),
          ),
          childWhenDragging: Opacity(
            opacity: 0.3,
            child: Container(width: 80, height: 80, color: Colors.blue),
          ),
          child: Container(width: 80, height: 80, color: Colors.blue),
        ),
        SizedBox(height: 100),
        // The drop target
        DragTarget<Color>(
          onAcceptWithDetails: (details) {
            setState(() => _targetColor = details.data);
          },
          builder: (context, candidateData, rejectedData) {
            return Container(
              width: 120, height: 120,
              color: candidateData.isNotEmpty
                  ? Colors.green[100] // Highlight when hovering
                  : _targetColor,
              child: Center(child: Text('Drop here')),
            );
          },
        ),
      ],
    );
  }
}

2. GestureDetector (Free-form Drag)

Use this for free movement of a widget anywhere on screen.

dart
class FreeDragWidget extends StatefulWidget {
  
  _FreeDragWidgetState createState() => _FreeDragWidgetState();
}

class _FreeDragWidgetState extends State<FreeDragWidget> {
  Offset _position = Offset(100, 100);

  
  Widget build(BuildContext context) {
    return Stack(
      children: [
        Positioned(
          left: _position.dx,
          top: _position.dy,
          child: GestureDetector(
            onPanUpdate: (details) {
              setState(() => _position += details.delta);
            },
            child: Container(
              width: 80, height: 80,
              decoration: BoxDecoration(
                color: Colors.blue,
                borderRadius: BorderRadius.circular(12),
              ),
              child: Center(
                child: Text('Drag me', style: TextStyle(color: Colors.white)),
              ),
            ),
          ),
        ),
      ],
    );
  }
}

3. LongPressDraggable

Like

text
Draggable
but only activates after a long press (common in list reordering):

dart
LongPressDraggable<String>(
  data: 'item_data',
  feedback: Material(
    elevation: 4,
    child: Container(
      width: 200, height: 60,
      color: Colors.blue[100],
      child: Text('Dragging...'),
    ),
  ),
  child: ListTile(title: Text('Long press to drag')),
)

When to Use Which

Use CaseWidget
Drag item to a specific drop zone
text
Draggable
+
text
DragTarget
Free movement anywhere
text
GestureDetector
with
text
onPanUpdate
Reorderable list
text
ReorderableListView
Drag to activate after hold
text
LongPressDraggable