Why is draggable widget not being placed in correct position?

Solution 1:

The main issue has to do with global position vs local position: Your Draggable widget gives global position whereas the Positioned inside your Stack takes local position. When there is no AppBar global and local positions match so the issue disappear but is still here.

So the real fix here is:

  1. Convert your global coordinates to locale ones:
RenderBox renderBox = context.findRenderObject();
onDragEnd(renderBox.globalToLocal(drag.offset));
  1. You now need a context. This context has to be local (the of the Draggable for example). So in the final implementation you can embed either the Stack or the Draggable in a StatelessWidget class in order to get a local context.

Here is my final implementation:

import 'package:flutter/material.dart';

main() {
  runApp(MaterialApp(
    home: DraggableTest(),
  ));
}

class DraggableTest extends StatefulWidget {
  static const routeName = '/draggable-test';

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

class _DraggableTestState extends State<DraggableTest> {
  Offset _dragOffset = Offset(0, 0);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Stack(
        children: <Widget>[
          Positioned(
            left: _dragOffset.dx,
            top: _dragOffset.dy,
            child: DragWidget(onDragEnd: onDragEnd),
          ),
        ],
      ),
    );
  }

  void onDragEnd(Offset offset) {
    setState(() {
      _dragOffset += offset;
    });
  }
}

class DragWidget extends StatelessWidget {
  final void Function(Offset) onDragEnd;

  const DragWidget({Key key, this.onDragEnd}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Draggable(
      child: Container(
        height: 120,
        width: 90,
        color: Colors.black,
      ),
      childWhenDragging: Container(
        height: 120,
        width: 90,
        color: Colors.grey,
      ),
      feedback: Container(
        height: 120,
        width: 90,
        color: Colors.red,
      ),
      onDragEnd: (drag) {
        RenderBox renderBox = context.findRenderObject();
        onDragEnd(renderBox.globalToLocal(drag.offset));
      },
    );
  }
}

Note that the offset returned by renderBox.globalToLocal(drag.offset) is the offset inside the Draggable (from the start position to the end position). It is why we need to compute the final offset by setting _dragOffset += offset.