import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:vitalapp/pages/home/controller.dart'; import 'package:vitalapp/store/store.dart'; /// 悬浮组件 class HoveringPatientCard extends StatefulWidget { const HoveringPatientCard({ Key? key, required this.child, required this.bgChild, this.alignment = AlignmentDirectional.topStart, this.textDirection, this.fit = StackFit.loose, this.clipBehavior = Clip.hardEdge, this.padding = EdgeInsets.zero, this.childSize = const Size(80, 80), }) : super(key: key); final AlignmentGeometry alignment; final TextDirection? textDirection; final StackFit fit; final Clip clipBehavior; /// 底部组件 final Widget bgChild; /// 悬浮组件 final Widget child; /// 悬浮组件宽高 final Size childSize; /// 距离四周边界 final EdgeInsets padding; @override _HoveringPatientCardState createState() => _HoveringPatientCardState(); } class _HoveringPatientCardState extends State { late ValueNotifier _topVN = ValueNotifier(0.0); late ValueNotifier _leftVN = ValueNotifier(0.0); late final ValueNotifier _panStart = ValueNotifier(false); @override Widget build(BuildContext context) { return Material( child: LayoutBuilder(builder: (context, constraints) { _topVN = ValueNotifier(186.0); _leftVN = ValueNotifier(constraints.maxWidth - widget.childSize.width); return Stack( alignment: widget.alignment, textDirection: widget.textDirection, fit: widget.fit, clipBehavior: widget.clipBehavior, children: [ widget.bgChild, buildSuspension( child: widget.child, maxWidth: constraints.maxWidth, maxHeight: constraints.maxHeight, ), ], ); }), ); } @override void initState() { super.initState(); } buildSuspension({ required Widget child, required double maxWidth, required double maxHeight, }) { return AnimatedBuilder( animation: Listenable.merge([ _topVN, _leftVN, ]), child: child, builder: (context, child) { return Positioned( top: _topVN.value, left: _leftVN.value, child: GestureDetector( onTap: () { // _onChangePatint(); }, onPanStart: (details) { _panStart.value = true; }, onPanEnd: (details) { _panStart.value = false; _leftVN.value = maxWidth - widget.childSize.width; }, onPanUpdate: (DragUpdateDetails detail) => _onPanUpdate( detail, maxHeight, maxWidth, ), child: AnimatedBuilder( animation: _panStart, child: child, builder: (BuildContext context, Widget? child) { if (_panStart.value) { return _buildHonver(child!); } return Container( child: child, ); }, ), ), ); }, ); } Widget _buildHonver(Widget child) { return Stack( children: [ SizedBox( height: 80, child: Row( children: [ Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: const [ Icon( Icons.keyboard_arrow_up_rounded, size: 30, ), Icon( Icons.keyboard_arrow_down_rounded, size: 30, ), ], ), SizedBox( height: 70, width: 70, child: child, ), ], ), ), ], ); } _onPanUpdate(DragUpdateDetails detail, double maxHeight, double maxWidth) { //用户手指滑动时,更新偏移,重新构建 //顶部 if (_topVN.value < widget.padding.top && detail.delta.dy < 0) { return; } // 左边 if (_leftVN.value < widget.padding.left && detail.delta.dx < 0) { return; } // 右边 if (_topVN.value > (maxHeight - widget.childSize.height - widget.padding.bottom) && detail.delta.dy > 0) { return; } // 下边 if (_leftVN.value > (maxWidth - widget.childSize.width - widget.padding.right) && detail.delta.dx > 0) { return; } _topVN.value += detail.delta.dy; print('update'); /// 这边可以后面改成全局移动 _leftVN.value += detail.delta.dx; // _leftVN.value = maxWidth - widget.childSize.width; // debugPrint("y:${_topVN.value}"); } }