如何在 Flutter 中移动屏幕中的小部件
How to move a widget in the screen in Flutter
我正在使用 flutter,我有一个 容器,使用此代码
new Container(
width: 50.0,
height: 50.0,
decoration: new BoxDecoration(
shape: BoxShape.circle)
我想让这个圆圈像这样在屏幕上移动
我该怎么做?
您正在寻找的是 Draggable
小部件。然后,您可以使用传递的 onDraggableCanceled
和可用于更新展示位置的偏移量来处理翻译
onDraggableCanceled :(velocity,offset){
//update the position here
}
更新
检查图像后,您需要 "Drop me here" 部分成为一个 DragTarget,它有一个方法 onAccept
,当您拖放 Draggable
时,该方法将处理逻辑]
您可以使用 Draggable
class 来拖动您想要拖动的项目并将其放置或粘贴到屏幕上的某个位置,您必须用 [=12= 包裹该项目] class。在 DragTarget
class onAccept
方法中,您可以在其中编写逻辑。您也可以在这里参考我的代码
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)),
);
}
}
这里是:
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);
},
),
),
],
);
}
}
首先,用 Positioned
将 Container
包裹在 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 !!");
}
希望对您有所帮助!
下面是整个过程
首先我们构建我们的骨架应用程序。然后我们可以将多个盒子嵌入到这个骨架中,每个盒子都有一个 Offset
、一个 Color
和一个 Label
string
。 Offset
确定框在给定时刻的位置,它具有初始状态和根据用户拖动框的位置更新的状态。
然后创建一个使用 DragTarget Class
的 static 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
我正在使用 flutter,我有一个 容器,使用此代码
new Container(
width: 50.0,
height: 50.0,
decoration: new BoxDecoration(
shape: BoxShape.circle)
我想让这个圆圈像这样在屏幕上移动
我该怎么做?
您正在寻找的是 Draggable
小部件。然后,您可以使用传递的 onDraggableCanceled
和可用于更新展示位置的偏移量来处理翻译
onDraggableCanceled :(velocity,offset){
//update the position here
}
更新
检查图像后,您需要 "Drop me here" 部分成为一个 DragTarget,它有一个方法 onAccept
,当您拖放 Draggable
时,该方法将处理逻辑]
您可以使用 Draggable
class 来拖动您想要拖动的项目并将其放置或粘贴到屏幕上的某个位置,您必须用 [=12= 包裹该项目] class。在 DragTarget
class onAccept
方法中,您可以在其中编写逻辑。您也可以在这里参考我的代码
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)),
);
}
}
这里是:
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);
},
),
),
],
);
}
}
首先,用 Positioned
将 Container
包裹在 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 !!");
}
希望对您有所帮助!
下面是整个过程
首先我们构建我们的骨架应用程序。然后我们可以将多个盒子嵌入到这个骨架中,每个盒子都有一个 Offset
、一个 Color
和一个 Label
string
。 Offset
确定框在给定时刻的位置,它具有初始状态和根据用户拖动框的位置更新的状态。
然后创建一个使用 DragTarget Class
的 static 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