【问题标题】:How to move a widget in the screen in Flutter如何在 Flutter 中移动屏幕中的小部件
【发布时间】:2018-09-13 23:17:42
【问题描述】:

我正在使用颤振,我有一个 容器 使用此代码的圆形形状

new Container(
 width: 50.0,
  height: 50.0,
   decoration: new BoxDecoration(
   shape: BoxShape.circle)

我想让这个圆圈像这样在屏幕上移动

我该怎么做?

【问题讨论】:

    标签: flutter dart move flutter-widget


    【解决方案1】:

    这里是:

    import 'package:flutter/material.dart';
    
    class SecondScreen extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(
              title: Text("Drag app"),
            ),
            body: HomePage(),
          ),
        );
      }
    }
    
    class HomePage extends StatefulWidget {
      @override
      State<StatefulWidget> createState() {
        return _HomePageState();
      }
    }
    
    class _HomePageState extends State<HomePage> {
      double width = 100.0, height = 100.0;
      Offset position ;
    
      @override
      void initState() {
        super.initState();
        position = Offset(0.0, height - 20);
      }
    
      @override
      Widget build(BuildContext context) {
        return Stack(
          children: <Widget>[
            Positioned(
              left: position.dx,
              //top: position.dy - height + 20,
              child: Draggable(
                child: Container(
                  width: width,
                  height: height,
                  color: Colors.blue,
                  child: Center(child: Text("Drag", style: Theme.of(context).textTheme.headline,),),
                ),
                feedback: Container(
                  child: Center(
                    child: Text("Drag", style: Theme.of(context).textTheme.headline,),),
                  color: Colors.red[800],
                  width: width,
                  height: height,
                ),
                onDraggableCanceled: (Velocity velocity, Offset offset){
                  setState(() => position = offset);
                },
              ),
            ),
          ],
        );
      }
    }
    

    【讨论】:

    • 哇!这就是我要找的东西!效果很好
    【解决方案2】:

    这里是如何做到这一点的整个过程

    首先我们构建我们的骨架应用程序。然后我们可以将多个盒子嵌入到这个骨架中,每个盒子都有一个Offset、一个Color和一个LabelstringOffset 确定盒子在给定时刻的位置,它具有初始状态和根据用户拖动盒子的位置更新的状态。

    然后创建一个使用DragTarget Classstatic UI element。我们可以将我们的Draggable Boxes 拖到这个DragTarget widget 上,以将其颜色更改为Draggable Box 的颜色。

    完整示例:

    class AppState extends State<App> {
      Color caughtColor = Colors.deepPurple;
    
      @override
      Widget build(BuildContext context) {
        return SafeArea(
          child: Stack(
            children: <Widget>[
               DragBox(Offset(0.0, 0.0), 'Box One', Colors.blueAccent),
               DragBox(Offset(150.0, 0.0), 'Box Two', Colors.orange),
               DragBox(Offset(300.0, 0.0), 'Box Three', Colors.lightGreen),
              Positioned(
                left: 125.0,
                bottom: 0.0,
                child: DragTarget(
                  onAccept: (Color color) {
                    caughtColor = color;
                  },
                  builder: (
                      BuildContext context,
                      List<dynamic> accepted,
                      List<dynamic> rejected,
                      ) {
                    return Container(
                      width: 150.0,
                      height: 150.0,
                      decoration: BoxDecoration(
                        color: accepted.isEmpty ? caughtColor : Colors.deepPurple.shade200,
                      ),
                      child: Center(
                        child: Text("Drag Here!", style: TextStyle(color: Colors.white)),
                      ),
                    );
                  },
                ),
              )
            ],
          ),
        );
      }
    }
    
    class DragBox extends StatefulWidget {
      final Offset initPos;
      final String label;
      final Color itemColor;
    
      DragBox(this.initPos, this.label, this.itemColor);
    
      @override
      DragBoxState createState() => DragBoxState();
    }
    
    class DragBoxState extends State<DragBox> {
      Offset position = Offset(0.0, 0.0);
    
      @override
      void initState() {
        super.initState();
        position = widget.initPos;
      }
    
      @override
      Widget build(BuildContext context) {
        return Positioned(
            left: position.dx,
            top: position.dy,
            child: Draggable(
              data: widget.itemColor,
              child: Container(
                width: 100.0,
                height: 100.0,
                color: widget.itemColor,
                child: Center(
                  child: Text(
                    widget.label,
                    style: TextStyle(
                      color: Colors.white,
                      decoration: TextDecoration.none,
                      fontSize: 20.0,
                    ),
                  ),
                ),
              ),
              onDraggableCanceled: (velocity, offset) {
                setState(() {
                  position = offset;
                });
              },
              feedback: Container(
                width: 120.0,
                height: 120.0,
                color: widget.itemColor.withOpacity(0.5),
                child: Center(
                  child: Text(
                    widget.label,
                    style: TextStyle(
                      color: Colors.white,
                      decoration: TextDecoration.none,
                      fontSize: 18.0,
                    ),
                  ),
                ),
              ),
            ));
      }
    }
    

    参考:Building a Drag and Drop Application

    【讨论】:

      【解决方案3】:

      您正在寻找的是Draggable 小部件。然后,您可以使用传递的 onDraggableCanceled 处理翻译和可用于更新展示位置的偏移量

      onDraggableCanceled :(velocity,offset){ 
      //update the position here
      } 
      

      更新

      检查图像后,您需要将“Drop me here”部分设为DragTarget,该部分具有onAccept 方法,当您拖放Draggable 时,该方法将处理逻辑

      【讨论】:

      • onDraggableCanceled 在这里是不必要的。他想要的是DragTarget
      • 啊,我看了图片后发现
      • @aziza 您好,如何在此处更新小部件的新位置?我是 Flutter 新手,不知道如何根据 offset 参数设置 Widget 的绝对位置。你能在这里提供一些代码吗?
      【解决方案4】:

      您可以使用Draggable 类来拖动要拖动的项目,并将其放置或粘贴到屏幕上的某个位置,您必须使用DragTarget 类包装该项目。在DragTargetonAccept 方法中可以编写逻辑。您也可以在这里参考我的代码

      import 'package:flutter/material.dart';
      void main() => runApp(new MyApp());
      
      class MyApp extends StatelessWidget {
        // This widget is the root of your application.
        @override
        Widget build(BuildContext context) {
          return new MaterialApp(
            title: 'Flutter Demo',
            theme: new ThemeData(
              primarySwatch: Colors.indigo,
            ),
            home: new MyHomePage(title: 'Flutter Demo Drag Box'),
          );
        }
      }
      
      class MyHomePage extends StatelessWidget {
        MyHomePage({Key key, this.title}) : super(key: key);
      
        final String title;
      
        @override
        Widget build(BuildContext context) {
          return new Scaffold(
            appBar: new AppBar(
              title: new Text(title),
            ),
            body:
                new DragGame(), // This trailing comma makes auto-formatting nicer for build methods.
          );
        }
      }
      
      class DragGame extends StatefulWidget {
        @override
        _DragGameState createState() => new _DragGameState();
      }
      
      class _DragGameState extends State<DragGame> {
        int boxNumberIsDragged;
      
        @override
        void initState() {
          boxNumberIsDragged = null;
          super.initState();
        }
      
        @override
        Widget build(BuildContext context) {
          return new Container(
              constraints: BoxConstraints.expand(),
              color: Colors.grey,
              child: new Stack(
                children: <Widget>[
                  buildDraggableBox(1, Colors.red, new Offset(30.0, 100.0)),
                  buildDraggableBox(2, Colors.yellow, new Offset(30.0, 200.0)),
                  buildDraggableBox(3, Colors.green, new Offset(30.0, 300.0)),
                ],
              ));
        }
      
        Widget buildDraggableBox(int boxNumber, Color color, Offset offset) {
          return new Draggable(
            maxSimultaneousDrags: boxNumberIsDragged == null || boxNumber == boxNumberIsDragged ? 1 : 0,
            child: _buildBox(color, offset),
            feedback: _buildBox(color, offset),
            childWhenDragging: _buildBox(color, offset, onlyBorder: true),
            onDragStarted: () {
              setState((){
                boxNumberIsDragged = boxNumber;
              });
            },
            onDragCompleted: () {
              setState((){
                boxNumberIsDragged = null;
              });
            },
            onDraggableCanceled: (_,__) {
              setState((){
                boxNumberIsDragged = null;
              });
            },
          );
        }
      
        Widget _buildBox(Color color, Offset offset, {bool onlyBorder: false}) {
          return new Container(
            height: 50.0,
            width: 50.0,
            margin: EdgeInsets.only(left: offset.dx, top: offset.dy),
            decoration: BoxDecoration(
                color: !onlyBorder ? color : Colors.grey,
                border: Border.all(color: color)),
          );
        }
      }
      

      【讨论】:

        【解决方案5】:

        首先,用PositionedContainer 包裹在Stack 中。

        然后,使用Pan Gesture 在您的Container 中实现Pan,并使用onPan... 方法处理Pan Gesture

        代码如下:

        偏移位置;

        @override
          void initState() {
            super.initState();
            position = Offset(10, 10);
          }    
        
        @override
            Widget build(BuildContext context) {
        
                double _width = MediaQuery.of(context).size.width;
                double _height = _width * 9 / 16;
        
        
                return GestureDetector(
                  onPanStart: (details) => _onPanStart(context, details),
                  onPanUpdate: (details) => _onPanUpdate(context, details, position),
                  onPanEnd: (details) => _onPanEnd(context, details),
                  onPanCancel: () => _onPanCancel(context),
        
                  child: SafeArea(
                    child: Stack(
                      children: <Widget>[
                        Positioned(
                          top: position.dy,
                          child: Container(
                            color: Colors.red,
                            width: _width,
                            height: _height,
                          ),
                        ),
                      ],
                    ),
                  ),
                );
              }
        
              void _onPanStart(BuildContext context, DragStartDetails details) {
                print(details.globalPosition.dy);
        
              }
        
              void _onPanUpdate(BuildContext context, DragUpdateDetails details, Offset offset) {
                setState(() {
                  position = details.globalPosition;
                });
              }
        
              void _onPanEnd(BuildContext context, DragEndDetails details) {
                print(details.velocity);
              }
        
              void _onPanCancel(BuildContext context) {
                print("Pan canceled !!");
              }
        

        希望这会有所帮助!

        【讨论】:

          猜你喜欢
          • 2023-03-03
          • 2020-02-18
          • 2019-11-21
          • 2022-07-01
          • 2019-06-21
          • 2021-07-31
          • 2020-08-19
          • 1970-01-01
          • 2023-04-02
          相关资源
          最近更新 更多