一,代码:
import 'package:flutter/material.dart';
class DragPage extends StatefulWidget {
@override
State<DragPage> createState() => _DragPageState();
}
class _DragPageState extends State<DragPage> {
final GlobalKey _parentKey = GlobalKey();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('拖动例子'),
),
body: Column(
children: [
//容器,占用一定高度
Container(
color: Colors.orange,
height: 100,
),
//下面的容器是被拖动widget可以移动的范围
Container(
width: 360,
height: 360,
child: Stack(
key: _parentKey,
children: [
Container(color: Colors.teal), //背景容器
//可拖动按钮在这里
DraggableFloatingActionButton(
child: Container(
width: 150,
height: 150,
decoration: ShapeDecoration(
shape: CircleBorder(),
color: Colors.red,
),
//按钮上的内容
child: Center(
child:const Text(
'可拖动',
style: const TextStyle(color: Colors.white, fontSize: 24),
),
),
),
initialOffset: const Offset(100, 100),
parentKey: _parentKey,
onPressed: () { //点击事件
print('Button is clicked');
},
),
],
),
),
],
),
);
}
}
//自定义可拖动的按钮
class DraggableFloatingActionButton extends StatefulWidget {
final Widget child;
final Offset initialOffset;
final VoidCallback onPressed;
final GlobalKey parentKey;
DraggableFloatingActionButton({
required this.child,
required this.initialOffset,
required this.onPressed,
required this.parentKey,
});
@override
State<StatefulWidget> createState() => _DraggableFloatingActionButtonState();
}
class _DraggableFloatingActionButtonState extends State<DraggableFloatingActionButton> {
final GlobalKey _key = GlobalKey();
bool _isDragging = false;
late Offset _offset;
late Offset _minOffset;
late Offset _maxOffset;
@override
void initState() {
super.initState();
_offset = widget.initialOffset;
WidgetsBinding.instance?.addPostFrameCallback(_setBoundary);
}
void _setBoundary(_) {
final RenderBox parentRenderBox =
widget.parentKey.currentContext?.findRenderObject() as RenderBox;
final RenderBox renderBox =
_key.currentContext?.findRenderObject() as RenderBox;
try {
final Size parentSize = parentRenderBox.size;
final Size size = renderBox.size;
setState(() {
_minOffset = const Offset(0, 0);
_maxOffset = Offset(
parentSize.width - size.width, parentSize.height - size.height);
});
} catch (e) {
print('catch: $e');
}
}
void _updatePosition(PointerMoveEvent pointerMoveEvent) {
double newOffsetX = _offset.dx + pointerMoveEvent.delta.dx;
double newOffsetY = _offset.dy + pointerMoveEvent.delta.dy;
if (newOffsetX < _minOffset.dx) {
newOffsetX = _minOffset.dx;
} else if (newOffsetX > _maxOffset.dx) {
newOffsetX = _maxOffset.dx;
}
if (newOffsetY < _minOffset.dy) {
newOffsetY = _minOffset.dy;
} else if (newOffsetY > _maxOffset.dy) {
newOffsetY = _maxOffset.dy;
}
setState(() {
_offset = Offset(newOffsetX, newOffsetY);
});
}
@override
Widget build(BuildContext context) {
return Positioned(
left: _offset.dx,
top: _offset.dy,
child: Listener(
onPointerMove: (PointerMoveEvent pointerMoveEvent) {
_updatePosition(pointerMoveEvent);
setState(() {
_isDragging = true;
});
},
onPointerUp: (PointerUpEvent pointerUpEvent) {
print('onPointerUp');
if (_isDragging) {
setState(() {
_isDragging = false;
});
} else {
widget.onPressed();
}
},
child: Container(
key: _key,
child: widget.child,
),
),
);
}
}
二,测试效果:
![]()