Search code examples
flutterlistenergesturedetector

Do we have onTapDown and Drag functionality in flutter?


I have a simple usecase which is some how super tricky for a beginner in flutter.

I need these values returned for the scenario explained below


There are 2 containers in a row (green and orange) enter image description here

  1. OnTapDown on green container it should return ‘Green’ (this is straight forward and done)
  2. Without lifting the finger off the screen, I drag my finger over the Orange container and I need that to return ‘Orange’


How do I solve this?


Solution

  • One solution could be to wrap your layout with GestureDetector and "guess" the position of your elements to then know where the drag ends.

    EDIT: Adding a real check on the target position to make it more robust thanks to @GoodSp33d comment:

    class DragView extends StatefulWidget {
      const DragView({Key? key}) : super(key: key);
    
      @override
      _DragViewState createState() => _DragViewState();
    }
    
    GlobalKey orangeContainerKey = GlobalKey();
    GlobalKey greenContainerKey = GlobalKey();
    
    class _DragViewState extends State<DragView> {
      Rect? getGlobalPaintBounds(GlobalKey element) {
        final renderObject = element.currentContext!.findRenderObject();
        var translation = renderObject?.getTransformTo(null).getTranslation();
        if (translation != null && renderObject?.paintBounds != null) {
          return renderObject?.paintBounds
              .shift(Offset(translation.x, translation.y));
        } else {
          return null;
        }
      }
    
      bool isInRect(double x, double y, Rect? rect) {
        if (rect != null)
          return x >= rect.left &&
              x <= rect.right &&
              y <= rect.bottom &&
              y >= rect.top;
        return false;
      }
    
      @override
      Widget build(BuildContext context) {
        double _cursorX = 0;
        double _cursorY = 0;
    
        return GestureDetector(
          onHorizontalDragUpdate: (details) {
            _cursorX = details.globalPosition.dx;
            _cursorY = details.globalPosition.dy;
          },
          onHorizontalDragEnd: (details) {
            if (isInRect(
                _cursorX, _cursorY, getGlobalPaintBounds(orangeContainerKey)))
              print("Orange");
            if (isInRect(
                _cursorX, _cursorY, getGlobalPaintBounds(greenContainerKey)))
              print("Green");
          },
          child: Row(
            children: [
              Expanded(
                child: Container(key: greenContainerKey, color: Colors.green),
              ),
              Expanded(
                child: Container(key: orangeContainerKey, color: Colors.orange),
              ),
            ],
          ),
        );
      }
    }
    
    

    Second edit moving the detection to the onDragUpdate and checks to make it happens only on rect changes:

        GlobalKey? currentObject;
    
          onHorizontalDragUpdate: (details) {
            _cursorX = details.globalPosition.dx;
            _cursorY = details.globalPosition.dy;
            if (isInRect(
                _cursorX, _cursorY, getGlobalPaintBounds(orangeContainerKey))) {
              if (currentObject == null || currentObject != orangeContainerKey) {
                print("Orange");
                currentObject = orangeContainerKey;
              }
            }
            if (isInRect(_cursorX, _cursorY,
                getGlobalPaintBounds(greenContainerKey))) if (currentObject ==
                    null ||
                currentObject != greenContainerKey) {
              print("Green");
              currentObject = greenContainerKey;
            }
          },