简体   繁体   中英

How to move a widget in the screen in Flutter

I am using flutter and i have a container with the shape of a circle using this code

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

I want to make this circle move on the screen like this

在此处输入图像描述

how can I do this?

Here it is:

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);
            },
          ),
        ),
      ],
    );
  }
}

What you are looking for is Draggable widget. You can then handle the translation using onDraggableCanceled which is passed and offset that you can be used to update the placement

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

Update

After checking the image you will need "Drop me here" part to be a DragTarget that has a method onAccept which will handles the logic when you drag and drop your Draggable

Here is the whole process of how to do this

First we build out our skeleton application. We then are able to embed multiple boxes into this skeleton, each one with an Offset , a Color and a Label string . The Offset determines where the box is at a given moment with it having an initial state and a state that gets updated based on where the user drags the box.

Then create a static UI element that makes use of the DragTarget Class . We can drag our Draggable Boxes onto this DragTarget widget to change it's color to the color of the Draggable Box .

Full example:

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,
                ),
              ),
            ),
          ),
        ));
  }
}

Ref : Building a Drag and Drop Application

在此处输入图片说明

You can use Draggable class for dragging the item which you want to drag and for placing it or sticking it to somewhere on the screen you have to wrap that item with DragTarget class. In DragTarget class onAccept method is there where you can write the logic. You can also take a reference to my code here it is

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)),
    );
  }
}

First, wrap your Container inside the Stack with Positioned .

Then, use Pan Gesture to implement a Pan in your Container and use onPan... methods to handle Pan Gesture

Here is code:

Offset position;

@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 !!");
      }

Hope this helps!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM