为什么可拖动小部件没有放置在正确的位置?

Chr*_*ris 4 dart flutter

我很难理解为什么在移动可拖动小部件后,它会被放置到比我放置它的位置低的另一个位置...我唯一能想到的是它增加了和...100px的高度Appbarstatus bar

我认为我做错了什么,所以我决定创建尽可能简单的示例,但它仍然在做同样的事情。

只是为了确认,我不想使用拖动目标或类似的东西......我只是希望可拖动的小部件准确地落在我放置该东西的位置。但是,我确实需要它在堆栈中

[编辑] 似乎删除AppBar可以让 Draggable 准确地落在您放置它的位置。但是,我不希望可拖动小部件位于状态栏后面,因此在添加 a 之后,SafeArea我遇到了类似的问题。[/编辑]

import 'package:flutter/material.dart';

class DraggableTest extends StatefulWidget {
  static const routeName = '/draggable-test';
  @override
  _DraggableTestState createState() => _DraggableTestState();
}

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

  Widget _dragWidget() {
    return Positioned(
      left: _dragOffset.dx,
      top: _dragOffset.dy,
      child: 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) {
          setState(() {
            _dragOffset = drag.offset;
          });
        },
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Stack(
        children: <Widget>[
          _dragWidget(),
        ],
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

Lul*_*ntu 7

主要问题与全球地位与本地地位有关:您的 Draggable 小部件提供全局位置,而 Stack 内的 Positioned 则采用本地位置。当 AppBar 全局和本地位置不匹配时,问题就会消失,但仍然存在。

所以这里真正的解决方法是:

  1. 将您的全局坐标转换为区域设置坐标:
RenderBox renderBox = context.findRenderObject();
onDragEnd(renderBox.globalToLocal(drag.offset));
Run Code Online (Sandbox Code Playgroud)
  1. 您现在需要一个上下文。该上下文必须是本地的(例如 Draggable 的上下文)。因此,在最终的实现中,您可以将 Stack 或 Draggable 嵌入 StatelessWidget 类中,以获得本地上下文。

这是我的最终实现:

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));
      },
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

请注意,返回的偏移量renderBox.globalToLocal(drag.offset)是 Draggable 内部的偏移量(从开始位置到结束位置)。这就是为什么我们需要通过设置来计算最终偏移量_dragOffset += offset