Search code examples
flutterflutter-layout

onMove in DragTarget throws exception when wrapped by Draggable


Suppose the DraggableDragTarget below is used like this:

Stack(
  children: [
    Positioned( top: 100, left: 100, child: DraggableDragTarget( title: 'one' )),
    Positioned( top: 300, left: 300, child: DraggableDragTarget( title: 'other' ))
  ],
 )

When I try to make the DraggableDragTarget widget Draggable and DragTaget both, the code below throws an exception, when I implement the onMove property.

If I remove the onMove property, the drag happens.

Since I expected the problem might be due to a drag operation the initial DragTarget Instance might be the Draggable instance itself, I added the operation ((1)). Nothing chances. Still exception.

How to make a Widget both Draggable and DragTarget?

import 'package:flutter/material.dart';

class DraggableDragTarget extends StatefulWidget {
  DraggableDragTarget({Key? key, required this.title}) : super(key: key);
  String title;

  @override
  State<DraggableDragTarget> createState() => _DraggableDragTargetState();
}

class _DraggableDragTargetState extends State<DraggableDragTarget> {
  @override
  Widget build(BuildContext context) {
    Widget inner = DragTarget(
      builder: (context, candidateData, rejectedData) =>
          Container(child: Text(widget.title, style: TextStyle(fontSize: 20))),
      onAccept: (something) {},
      onLeave: (something) {},

      // if this handler gets defined, a drag throws an exception
      // and the drag stops immediately
      onMove: (someDragTargetDetail) {},

      onWillAccept: (something) {
        if (null == something) {
          return false;
        }
        print(widget.toString() + ' vs. ' + something.toString());
        // ((1))
        if (something == widget) {
          return false;
        } else {
          return true;
        }
      },
    );

    Widget feedback = Text('Feedback placeholder',
        style: TextStyle(fontSize: 20, color: Colors.green));

    return Draggable(child: inner, feedback: feedback);
  }
}

Solution

  • You need to provide data to the Draggable widget. Your example code works for me with that change.

    return Draggable(
      data: widget.title,
      feedback: feedback,
      child: inner,
    );
    

    I just used the title for convenience. Replace it with whatever data you want to actually represent the item being dragged.