import 'package:flutter/material.dart';
class DragFloatPage extends StatefulWidget {
const DragFloatPage({super.key});
@override
State<StatefulWidget> createState() => _DragFloatPageState();
}
class _DragFloatPageState extends State<DragFloatPage>{
final _topVN = ValueNotifier(0.0);
final _leftVN = ValueNotifier(0.0);
Size? childSize;
Size? parentSize;
@override
Widget build(BuildContext context) {
return Align(
alignment: Alignment.center,
child: Container(
color: Colors.amber,
child: AnimatedBuilder(
animation: Listenable.merge([_topVN,_leftVN]),
builder: (context,child){
return CustomSingleChildLayout(
delegate: PolarLayoutDelegate((childSize){
this.childSize = childSize;
},(parentSize){
this.parentSize = parentSize;
},_topVN,_leftVN),
child: GestureDetector(
onPanUpdate: (DragUpdateDetails e){
if(childSize == null || parentSize == null)return;
var preTop = _topVN.value;
var preLeft = _leftVN.value;
var currentTop = preTop + e.delta.dy;
var currentLeft = preLeft + e.delta.dx;
if (currentTop <=0 ) {
_topVN.value = 0;
return;
}
if (currentLeft < 0) {
_leftVN.value = 0;
return;
}
var maxWidth = parentSize!.width;
var maxHeight = parentSize!.height;
if (currentTop > (maxHeight - childSize!.height)) {
_topVN.value = maxHeight - childSize!.height;
return;
}
if (currentLeft > (maxWidth - childSize!.width)) {
_leftVN.value = maxWidth - childSize!.width;
return;
}
_topVN.value = currentTop;
_leftVN.value = currentLeft;
},
child: SizedBox(
width: 50,
height: 50,
child: ColoredBox(
color: Colors.green,
),
),
),
);
},
),
),
);
}
}
class PolarLayoutDelegate extends SingleChildLayoutDelegate {
final ValueNotifier<double> _topVN;
final ValueNotifier<double> _leftVN;
ValueChanged<Size> childSizeCallBack;
ValueChanged<Size> parentSizeCallBack;
PolarLayoutDelegate(this.childSizeCallBack,this.parentSizeCallBack,this._topVN,this._leftVN);
@override
bool shouldRelayout(covariant PolarLayoutDelegate oldDelegate) => true;
@override
Size getSize(BoxConstraints constraints) {
final radius = constraints.biggest.shortestSide;
return Size(radius, radius);
}
@override
Offset getPositionForChild(Size size, Size childSize) {
childSizeCallBack(childSize);
parentSizeCallBack(size);
return Offset(_leftVN.value, _topVN.value);
}
@override
BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
return constraints.loosen();
}
}