Search code examples
flutterflutter-layout

Draggable widget not drop at exact position Flutter


I have a Draggable like this. Most tutorial video is to use Draggable on full screen, but i just want to use it in a small area on the screen.

class DragBox extends StatefulWidget {
  final Offset initPos;
  final AssetImage image;

  DragBox(this.initPos, this.image);

  @override
  _DragBoxState createState() => _DragBoxState();
}

class _DragBoxState extends State<DragBox> {
  Offset position = Offset.zero;
  double top = 0;
  double left = 0;

  @override
  void initState() {
    super.initState();
    position = widget.initPos;
  }

  Widget _dragChild() {
    return CircleAvatar(
      backgroundImage: widget.image,
      backgroundColor: colorPlayerBackground,
    );
  }

  @override
  Widget build(BuildContext context) {
    return Positioned(
      left: position.dx,
      top: position.dy,
      child: Draggable(
        data: [widget.image],
        child: _dragChild(),
        onDraggableCanceled: (velocity, offset) {
          setState(() {
            position = offset;
          });
        },
        childWhenDragging: Opacity(
          opacity: 0.5,
          child: _dragChild(),
        ),
        feedback: _dragChild(),
      ),
    );
  }
}

Inside a Card container with a DragTarget.

Container(
    width: double.infinity,
    child: Card(
      child: Stack(
        children: <Widget>[
          DragBox(Offset(0.0, 0.0), AssetImage(playerAnthonyMartial)),
          DragBox(Offset(150.0, 0.0), AssetImage(playerBrunoFernandes)),
          Positioned(
            left: 75.0,
            bottom: 0.0,
            child: Container(
              width: 120,
              height: 120,
              color: Colors.black,
              child: DragTarget(
                onWillAccept: (data) {
                  return true;
                },
                onAccept: (data) {
                  accept = true;
                },
                builder: (
                  BuildContext context,
                  List<dynamic> accepted,
                  rejected,
                ) {
                  return accept
                      ? Image.asset('assets/images/AnthonyMartial.png')
                      : Container();
                },
              ),
            ),
          )
        ],
      ),
    ),
  ),

But this happens when i drop it How does that happen, how to fix it?

I follow a guide on youtube, but when i drag the Draggable on the target nothing seem to happen, how is the data passed. I quite not understand how it works. Please help!!!


Solution

  • you need to add small offset correction and remove card if you don't use it.

    enter image description here

    import 'package:flutter/material.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: Scaffold(
            body: SafeArea(
              child: MyHomePage(),
            ),
          ),
        );
      }
    }
    
    const playerAnthonyMartial = 'assets/AnthonyMartial.png';
    const playerBrunoFernandes = 'assets/BrunoFernandes.png';
    const colorPlayerBackground = Colors.white;
    
    class MyHomePage extends StatefulWidget {
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      @override
      Widget build(BuildContext context) {
        bool accept;
        return Stack(
          children: <Widget>[
            DragBox(Offset(0.0, 0.0), AssetImage(playerAnthonyMartial)),
            DragBox(Offset(150.0, 0.0), AssetImage(playerBrunoFernandes)),
            Positioned(
              left: 75.0,
              bottom: 0.0,
              child: Container(
                width: 120,
                height: 120,
                color: Colors.black,
                child: DragTarget(
                  onWillAccept: (data) {
                    return true;
                  },
                  onAccept: (data) {
                    accept = true;
                  },
                  builder: (
                    BuildContext context,
                    List<dynamic> accepted,
                    rejected,
                  ) {
                    return Container(child: Text('hey'));
                  },
                ),
              ),
            )
          ],
        );
      }
    }
    
    class DragBox extends StatefulWidget {
      final Offset initPos;
      final AssetImage image;
    
      DragBox(this.initPos, this.image);
    
      @override
      _DragBoxState createState() => _DragBoxState();
    }
    
    class _DragBoxState extends State<DragBox> {
      Offset position = Offset.zero;
      double top = 0;
      double left = 0;
    
      @override
      void initState() {
        super.initState();
        position = widget.initPos;
      }
    
      Widget _dragChild() {
        return CircleAvatar(
          radius: 20,
          backgroundImage: widget.image,
          backgroundColor: colorPlayerBackground,
        );
      }
    
      @override
      Widget build(BuildContext context) {
        print(position);
        return Positioned(
          left: position.dx,
          top: position.dy,
          child: Draggable(
            data: [widget.image],
            child: _dragChild(),
            onDraggableCanceled: (velocity, offset) {
              setState(() {
                position = offset - Offset(0, 20);
              });
            },
            childWhenDragging: Opacity(
              opacity: 0.5,
              child: _dragChild(),
            ),
            feedback: _dragChild(),
          ),
        );
      }
    }