diff --git a/CHANGELOG.md b/CHANGELOG.md index 03e42d3..8d301d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ + +## [3.0.3] 新增页面悬浮托动按钮 ## [3.0.2] 文档更新 ## [3.0.1] RoteFloatingButton 支持设置按钮大小 diff --git a/README.md b/README.md index f77acf6..5be9c2b 100644 --- a/README.md +++ b/README.md @@ -144,3 +144,45 @@ Flutter抖动动画组件,FLutter颤动动画 }, ) ``` + +#### 6 页面悬浮可托动按钮 + +![](images/float_fab_button.gif) +``` + +class _Exam223HomePageState extends State { + //Stack使用的Key + final GlobalKey _parentKey = GlobalKey(); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: SizedBox( + width: double.infinity, + height: double.infinity, + child: Stack( + key: _parentKey, + children: [ + Container(color: Colors.blueGrey), + + DraggableFloatingActionButton( + child: Container( + width: 60, + height: 60, + decoration: const ShapeDecoration( + shape: CircleBorder(), + color: Colors.white, + ), + child: const Icon(Icons.add), + ), + initialOffset: const Offset(120, 70), + parentKey: _parentKey, + onPressed: () {}, + ), + ], + ), + ), + ); + } +} +``` diff --git a/example/lib/main.dart b/example/lib/main.dart index 946650a..dab14f9 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -68,7 +68,18 @@ class _Exam220HomePageState extends State { return Example309(); })); }, - child: Text("开源中图底部菜单")) + child: Text("开源中图底部菜单")), + + ElevatedButton( + onPressed: () { + Navigator.of(context).push(new MaterialPageRoute( + builder: (BuildContext context) { + return Exam223HomePage(); + })); + }, + child: Text("可托动的悬浮按钮")), + + ], ), //向上弹出的按钮组件 @@ -242,3 +253,52 @@ class _ExampleState extends State { ); } } + + + + + +class Exam223HomePage extends StatefulWidget { + const Exam223HomePage({Key? key}) : super(key: key); + + @override + State createState() => _Exam223HomePageState(); +} + +///代码清单2-27 可托动的悬浮按钮 + +class _Exam223HomePageState extends State { + //Stack使用的Key + final GlobalKey _parentKey = GlobalKey(); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: SizedBox( + width: double.infinity, + height: double.infinity, + child: Stack( + key: _parentKey, + children: [ + Container(color: Colors.blueGrey), + + DraggableFloatingActionButton( + child: Container( + width: 60, + height: 60, + decoration: const ShapeDecoration( + shape: CircleBorder(), + color: Colors.white, + ), + child: const Icon(Icons.add), + ), + initialOffset: const Offset(120, 70), + parentKey: _parentKey, + onPressed: () {}, + ), + ], + ), + ), + ); + } +} \ No newline at end of file diff --git a/images/float_fab_button.gif b/images/float_fab_button.gif new file mode 100644 index 0000000..cd8be53 Binary files /dev/null and b/images/float_fab_button.gif differ diff --git a/lib/shake_animation_widget.dart b/lib/shake_animation_widget.dart index ec91b95..2926532 100644 --- a/lib/shake_animation_widget.dart +++ b/lib/shake_animation_widget.dart @@ -9,4 +9,5 @@ export 'package:shake_animation_widget/src/rote_floating_button.dart'; export 'package:shake_animation_widget/src/animated_button.dart'; export 'package:shake_animation_widget/src/animated_button_statue.dart'; export 'package:shake_animation_widget/src/bottom_round_flow_menu.dart'; -export 'package:shake_animation_widget/src/rote_flow_button_menu.dart'; \ No newline at end of file +export 'package:shake_animation_widget/src/rote_flow_button_menu.dart'; +export 'package:shake_animation_widget/src/draggable_floating_action_button.dart'; \ No newline at end of file diff --git a/lib/src/draggable_floating_action_button.dart b/lib/src/draggable_floating_action_button.dart new file mode 100644 index 0000000..aa91364 --- /dev/null +++ b/lib/src/draggable_floating_action_button.dart @@ -0,0 +1,113 @@ +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; + +//静态路由配置///代码清单2-27-1 可托动的悬浮按钮 +///代码路径 lib/code2/draggable_floating_action_button.dart +class DraggableFloatingActionButton extends StatefulWidget { + final Widget child; + final Offset initialOffset; + final VoidCallback onPressed; + GlobalKey> parentKey; + DraggableFloatingActionButton({ + required this.child, + required this.initialOffset, + required this.onPressed, + required this.parentKey, + }); + + @override + State createState() => _DraggableFloatingActionButtonState(); +} + +class _DraggableFloatingActionButtonState + extends State { + //托动按钮使用的Key + 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(_initBoundary); + } + //页面第一帧绘制完成后调用 + void _initBoundary(_) { + //获取获取组件的 RenderBox + final RenderBox parentRenderBox = + widget.parentKey.currentContext?.findRenderObject() as RenderBox; + //获取托动按钮组件的 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'); + } + } + ///代码清单2-27-3 计算按钮位置 + 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); + }); + } + ///代码清单2-27-2 可托动的悬浮按钮 + @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, + ), + ), + ); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index d021429..0fd3ea4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: shake_animation_widget description: 抖动动画、向上弹出动画、抖动文本、垂直圆形菜单、底部圆形菜单、动画进度按钮 -version: 3.0.2 +version: 3.0.3 homepage: https://github.com/zhaolongs/flutter_shake_animation_widget.git environment: