Search code examples
flutterdartflutter-layoutdraggableflutter-animation

How to drag elements inside a Stack using Draggable in Flutter?


I have the following code:

import 'package:flutter/material.dart';

class PScreen extends StatefulWidget {
  @override
  _PScreenState createState() => _PScreenState();
}

class _PScreenState extends State<PScreen> {
  double width = 70.0, height = 70.0;
  double _x = 0;
  double _y = 0;

  AppBar appBar;

  Widget circle() {
    return Container(
      width: width,
      height: height,
      child: Center(
        child: Text(
          "Drag",
          style: Theme.of(context).textTheme.headline,
        ),
      ),
      decoration: BoxDecoration(
        shape: BoxShape.circle,
        color: Colors.blue,
      ),
    );
  }

  Widget draggable() {
    return Positioned(
      left: _x,
      top: _y,
      child:  Draggable(
          child: circle(),
          feedback: circle(),
          childWhenDragging: Container(),
          onDragEnd: (dragDetails) {
            setState(
              () {
                _x = dragDetails.offset.dx;
                // We need to remove offsets like app/status bar from Y
                _y = dragDetails.offset.dy -
                    appBar.preferredSize.height -
                    MediaQuery.of(context).padding.top;
              },
            );
          },
        ),
    );
  }

  @override
  Widget build(BuildContext context) {
    appBar = AppBar(
      title: Text('Drag'),
      leading: BackButton(onPressed: () {
        Navigator.pop(context, false);
      }),
    );
    return Scaffold(
      appBar: appBar,
      body: Stack(
        children: <Widget>[
          draggable(),
          circle(),
        ],
      ),
    );
  }
}

With this code, I can drag a circle on the screen and when I put it, the circle stays in the position I left, that's what I want to do. My problem is that I need to draw other things on the screen, like to draw another circle. When I put other elements within the Stack I can't drag my draggable circle anymore. If you remove "circle()" inside the Stack, the code will work, but with other elements inside the Stack it isn't working.

How can I do this? Thank you.


Solution

  • You are placing the second circle on top of the first one, that is why it is not working. Instead, wrap it with a position widget and align the second circle correctly so that you can interact with the first one without any problem.

      Positioned(
            left:0.0,
            bottom:0.0,
            child: circle()),
    

    So, your complete code will look like

     class PScreen extends StatefulWidget {
      @override
      _PScreenState createState() => _PScreenState();
    }
    
    class _PScreenState extends State<PScreen> {
      double width = 70.0, height = 70.0;
      double _x = 0;
      double _y = 0;
    
      AppBar appBar;
    
      Widget circle() {
        return Container(
          width: width,
          height: height,
          child: Center(
            child: Text(
              "Drag",
              style: Theme.of(context).textTheme.headline,
            ),
          ),
          decoration: BoxDecoration(
            shape: BoxShape.circle,
            color: Colors.blue,
          ),
        );
      }
    
      Widget draggable() {
        return Positioned(
          left: _x,
          top: _y,
          child:  Draggable(
              child: circle(),
              feedback: circle(),
              childWhenDragging: Container(),
              onDragEnd: (dragDetails) {
                setState(
                  () {
                    _x = dragDetails.offset.dx;
                    // We need to remove offsets like app/status bar from Y
                    _y = dragDetails.offset.dy -
                        appBar.preferredSize.height -
                        MediaQuery.of(context).padding.top;
                  },
                );
              },
            ),
        );
      }
    
      @override
      Widget build(BuildContext context) {
        appBar = AppBar(
          title: Text('Drag'),
          leading: BackButton(onPressed: () {
            Navigator.pop(context, false);
          }),
        );
        return Scaffold(
          appBar: appBar,
          body: Stack(
            children: <Widget>[
              draggable(),
              Positioned(
                left:0.0,
                bottom:0.0,
                child: circle()),
            ],
          ),
        );
      }
    }