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

Flutter 为什么可拖动小部件没有放置在正确的位置?,flutter,dart,Flutter,Dart,我很难理解为什么在移动了一个可拖动的小部件后,它会被放置到另一个位置,比我放置它的位置低大约100px。。。我唯一能想到的是它增加了Appbar和状态栏的高度 我认为我做错了什么,所以我决定创建一个最简单的示例,它仍然在做同样的事情 只是确认一下,我不想使用拖拽目标,或者类似的东西。。。我只想让这个可拖动的小部件精确地降落在我放置东西的地方。但是,我确实需要它在堆栈中 [编辑]似乎移除AppBar可以让Dragable准确地降落在您放置它的位置。但是,我不希望可拖动的小部件位于状态栏后面,因此在

我很难理解为什么在移动了一个可拖动的小部件后,它会被放置到另一个位置,比我放置它的位置低大约
100px
。。。我唯一能想到的是它增加了
Appbar
状态栏的高度

我认为我做错了什么,所以我决定创建一个最简单的示例,它仍然在做同样的事情

只是确认一下,我不想使用拖拽目标,或者类似的东西。。。我只想让这个可拖动的小部件精确地降落在我放置东西的地方。但是,我确实需要它在堆栈中

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

导入“包装:颤振/材料.省道”;
类DragableTest扩展StatefulWidget{
静态常量routeName='/draggable test';
@凌驾
_DragableTestState createState()=>_DragableTestState();
}
类_DragableTestState扩展状态{
偏移量_dragOffset=偏移量(0,0);
Widget_dragWidget(){
返回定位(
左:_dragOffset.dx,
顶部:_dragOffset.dy,
孩子:拖拉(
子:容器(
身高:120,
宽度:90,
颜色:颜色,黑色,
),
ChildWhenDraging:容器(
身高:120,
宽度:90,
颜色:颜色。灰色,
),
反馈:集装箱(
身高:120,
宽度:90,
颜色:颜色,红色,
),
onDragEnd:(拖动){
设置状态(){
_dragOffset=drag.offset;
});
},
),
);
}
@凌驾
小部件构建(构建上下文){
返回脚手架(
appBar:appBar(),
主体:堆栈(
儿童:[
_dragWidget(),
],
),
);
}
}

主要问题与全局位置与本地位置有关:您的可拖动小部件提供全局位置,而位于堆栈内部的小部件采用本地位置。当没有AppBar全局和本地位置匹配时,问题会消失,但仍然存在

因此,真正的解决办法是:

  • 将全局坐标转换为区域设置坐标:
  • 你知道我们需要一个背景。此上下文必须是本地的(例如,可拖动的)。因此,在最终的实现中,您可以在无状态小部件类中嵌入堆栈或Draggable,以获得本地上下文
  • 以下是我的最终实现:

    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));
          },
        );
      }
    }
    
    导入“包装:颤振/材料.省道”;
    main(){
    runApp(材料应用程序)(
    主页:DragTableTest(),
    ));
    }
    类DragableTest扩展StatefulWidget{
    静态常量routeName='/draggable test';
    @凌驾
    _DragableTestState createState()=>_DragableTestState();
    }
    类_DragableTestState扩展状态{
    偏移量_dragOffset=偏移量(0,0);
    @凌驾
    小部件构建(构建上下文){
    返回脚手架(
    appBar:appBar(),
    主体:堆栈(
    儿童:[
    定位(
    左:_dragOffset.dx,
    顶部:_dragOffset.dy,
    孩子:DragWidget(onDragEnd:onDragEnd),
    ),
    ],
    ),
    );
    }
    void onDragEnd(偏移){
    设置状态(){
    _dragOffset+=偏移量;
    });
    }
    }
    类DragWidget扩展了无状态小部件{
    最终空隙函数(偏移量)在拉根端;
    const DragWidget({Key-Key,this.onDragEnd}):super(Key:Key);
    @凌驾
    小部件构建(构建上下文){
    回拖式(
    子:容器(
    身高:120,
    宽度:90,
    颜色:颜色,黑色,
    ),
    ChildWhenDraging:容器(
    身高:120,
    宽度:90,
    颜色:颜色。灰色,
    ),
    反馈:集装箱(
    身高:120,
    宽度:90,
    颜色:颜色,红色,
    ),
    onDragEnd:(拖动){
    RenderBox RenderBox=context.findenderobject();
    onDragEnd(renderBox.globalToLocal(drag.offset));
    },
    );
    }
    }
    

    注意renderBox.globalToLocal(drag.offset)
    返回的偏移量是可拖动范围内的偏移量(从开始位置到结束位置)。这就是为什么我们需要通过设置
    \u dragOffset+=offset

    来计算最终偏移量的原因。主要问题与全局位置与局部位置有关:您的可拖动小部件提供全局位置,而堆栈中的定位则采用局部位置。当没有AppBar全局和本地位置匹配时,问题会消失,但仍然存在

    因此,真正的解决办法是:

  • 将全局坐标转换为区域设置坐标:
  • 你知道我们需要一个背景。此上下文必须是本地的(例如,可拖动的)。因此,在最终的实现中,您可以在无状态小部件类中嵌入堆栈或Draggable,以获得本地上下文
  • 以下是我的最终实现:

    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));
          },
        );
      }
    }
    
    导入“包装:颤振/材料.省道”;
    main(){
    runApp(材料应用程序)(
    主页:DragTableTest(),
    ));
    }
    类DragableTest扩展StatefulWidget{
    静态常量routeName='/draggable test';
    @凌驾
    _DragableTestState createState()=>_DragableTestState();
    }
    类_DragableTestState扩展状态{
    偏移量_dragOffset=偏移量(0,0);
    @凌驾
    小部件构建(构建上下文){
    返回脚手架(
    appBar:appBar(),
    主体:堆栈(
    儿童:[
    定位(
    左:_dragOffset.dx,
    顶部:_dragOffset.dy,
    孩子:DragWidget(onDragEnd:onDragEnd),
    ),
    ],
    ),
    );
    }
    void onDragEnd(偏移){
    设置状态(){
    _dragOffset+=偏移量;
    });
    }
    }
    类DragWidget扩展了无状态小部件{
    最终空隙函数(偏移)