在 Flutter 中,GestureDetector 组件可以识别和处理各种手势,包括拖拽手势。利用这一点,并结合Stack中的Positioned即可轻松实现拖拽view功能。
实现效果如下:
效果示例
onPanUpdate 是Flutter 中 GestureDetector 组件的一个属性,用于处理拖动(平移)手势的更新。当用户在屏幕上拖动手指时,onPanUpdate 会被触发,并且会提供一个 DragUpdateDetails对象,DragUpdateDetails其中包含了关于拖动事件的信息。
// 可拖动控件边距位置
double _top = 0;
double _left = 0;
// 可拖动控件的大小
final double _width = 100;
final double _height = 100;
Stack(
children: [
// 可拖动的控件
Positioned(
top: _top,
left: _left,
child: GestureDetector(
onPanUpdate: (details) {
setState(() {
double newTop = _top + details.delta.dy;
double newLeft = _left + details.delta.dx;
// 更新位置
_top = newTop;
_left = newLeft;
});
},
child: Container(
width: _width,
height: _height,
color: Colors.red,
)),
),
],
)
在拖拽控件时通常是不希望控件超出屏幕外的,因此需要对可拖拽控件的位置做出限制。
// 获取屏幕尺寸
double screenWidth = MediaQuery.of(context).size.width;
double screenHeight = MediaQuery.of(context).size.height;
// 计算边界
const double topBoundary = 0;
final double bottomBoundary = screenHeight - _height;
const double leftBoundary = 0;
final double rightBoundary = screenWidth - _width;
// 检查是否超出边界
newTop = newTop < topBoundary ? topBoundary : newTop;
newTop = newTop > bottomBoundary ? bottomBoundary : newTop;
newLeft = newLeft < leftBoundary ? leftBoundary : newLeft;
newLeft = newLeft > rightBoundary ? rightBoundary : newLeft;
完整代码如下:
class DragPage extends StatefulWidget {
const DragPage({Key? key}) : super(key: key);
@override
State<DragPage> createState() => _DragPageState();
}
class _DragPageState extends State<DragPage> {
// 可拖动控件边距位置
double _top = 0;
double _left = 0;
// 可拖动控件的大小
final double _width = 100;
final double _height = 100;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("DragPage"),
),
body: Stack(
children: [
// 可拖动的控件
Positioned(
top: _top,
left: _left,
child: GestureDetector(
onPanUpdate: (details) {
setState(() {
double newTop = _top + details.delta.dy;
double newLeft = _left + details.delta.dx;
// 获取屏幕尺寸
double screenWidth = MediaQuery.of(context).size.width;
double screenHeight = MediaQuery.of(context).size.height;
// 计算边界
const double topBoundary = 0;
final double bottomBoundary = screenHeight - _height;
const double leftBoundary = 0;
final double rightBoundary = screenWidth - _width;
// 检查是否超出边界
newTop = newTop < topBoundary ? topBoundary : newTop;
newTop =
newTop > bottomBoundary ? bottomBoundary : newTop;
newLeft = newLeft < leftBoundary ? leftBoundary : newLeft;
newLeft =
newLeft > rightBoundary ? rightBoundary : newLeft;
// 更新位置
_top = newTop;
_left = newLeft;
});
},
child: Container(
width: _width,
height: _height,
color: Colors.red,
)),
),
],
));
}
}
以上就可实现view在屏幕内自由拖动的效果。