From 8f8e51907e6e59254ee810556574027290966b2f Mon Sep 17 00:00:00 2001 From: toly <1981462002@qq.com> Date: Tue, 17 Nov 2020 21:22:35 +0800 Subject: [PATCH] =?UTF-8?q?:sparkles:=20=E4=BC=98=E5=8C=96=E6=8B=96?= =?UTF-8?q?=E6=8B=BD=E6=B5=AE=E9=92=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/components/permanent/burst_flow.dart | 116 +++++++++ lib/components/permanent/color_wrapper.dart | 32 ++- .../permanent/overlay_tool_wrapper.dart | 228 ++++++++++-------- 3 files changed, 273 insertions(+), 103 deletions(-) create mode 100644 lib/components/permanent/burst_flow.dart diff --git a/lib/components/permanent/burst_flow.dart b/lib/components/permanent/burst_flow.dart new file mode 100644 index 0000000..0a036a6 --- /dev/null +++ b/lib/components/permanent/burst_flow.dart @@ -0,0 +1,116 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020/11/17 +/// contact me by email 1981462002@qq.com +/// 说明: + +class BurstFlow extends StatefulWidget { + final List children; + final Widget menu; + final double startAngle; + + final double swapAngle; + + BurstFlow({Key key,@required this.children, + this.startAngle = 30 + 90.0, + this.swapAngle = 120, + @required this.menu}) : super(key: key); + + + @override + BurstFlowState createState() => BurstFlowState(); +} + +class BurstFlowState extends State + with SingleTickerProviderStateMixin { + AnimationController _controller; + bool _closed = true; + + @override + void initState() { + super.initState(); + _controller = + AnimationController(duration: Duration(milliseconds: 300), vsync: this) + ..addStatusListener((status) { + if (status == AnimationStatus.completed) {} + }); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Flow( + delegate: _CircleFlowDelegate(_controller, + swapAngle: widget.swapAngle, startAngle: widget.startAngle), + children: [ + ...widget.children, + GestureDetector(onTap: toggle, child: widget.menu) + ], + ); + } + + toggle() { + if (_closed) { + _controller.forward(); + } else { + _controller.reverse(); + } + _closed = !_closed; + } +} + +class _CircleFlowDelegate extends FlowDelegate { + final Animation repaint; + + _CircleFlowDelegate(this.repaint, + {this.startAngle = 30 + 90.0, this.swapAngle = 120}) + : super(repaint: repaint); + + final double startAngle; + + final double swapAngle; + + @override //绘制孩子的方法 + void paintChildren(FlowPaintingContext context) { + double radius = context.size.shortestSide / 2; + if (repaint.value > 0.3) { + var count = context.childCount - 1; + var perRad = swapAngle / 180 * pi / (count - 1); + double rotate = startAngle / 180 * pi; + for (int i = 0; i < count; i++) { + var cSizeX = context.getChildSize(i).width / 2; + var cSizeY = context.getChildSize(i).height / 2; + + var offsetX = + repaint.value * (radius - cSizeX) * cos(i * perRad + rotate) + + radius; + var offsetY = + repaint.value * (radius - cSizeY) * sin(i * perRad + rotate) + + radius; + + context.paintChild(i, + transform: Matrix4.translationValues( + offsetX - cSizeX, offsetY - cSizeY, 0.0), + opacity: repaint.value); + } + } + + context.paintChild(context.childCount - 1, + transform: Matrix4.translationValues( + radius - context.getChildSize(context.childCount - 1).width / 2, + radius - context.getChildSize(context.childCount - 1).height / 2, + 0.0)); + } + + @override + bool shouldRepaint(FlowDelegate oldDelegate) { + return true; + } +} diff --git a/lib/components/permanent/color_wrapper.dart b/lib/components/permanent/color_wrapper.dart index 5805b7a..4853d8d 100644 --- a/lib/components/permanent/color_wrapper.dart +++ b/lib/components/permanent/color_wrapper.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; /// create by 张风捷特烈 on 2020/9/3 /// contact me by email 1981462002@qq.com -/// 说明: +/// 说明: class WrapColor extends StatelessWidget { final Widget child; @@ -12,10 +12,10 @@ class WrapColor extends StatelessWidget { WrapColor( {this.child, - this.color = Colors.blue, - this.radius = 5, - this.padding = - const EdgeInsets.only(left: 4, right: 4, top: 0, bottom: 0)}); + this.color = Colors.blue, + this.radius = 5, + this.padding = + const EdgeInsets.only(left: 4, right: 4, top: 0, bottom: 0)}); @override Widget build(BuildContext context) { @@ -27,4 +27,24 @@ class WrapColor extends StatelessWidget { borderRadius: BorderRadius.all(Radius.circular(radius))), ); } -} \ No newline at end of file +} + +class Circled extends StatelessWidget { + final Widget child; + final Color color; + final double radius; + + Circled({this.child, this.color = Colors.blue, this.radius = 15}); + + @override + Widget build(BuildContext context) { + return Container( + width: radius * 2, + height: radius * 2, + child: child, + decoration: BoxDecoration( + color: color, + borderRadius: BorderRadius.all(Radius.circular(radius))), + ); + } +} diff --git a/lib/components/permanent/overlay_tool_wrapper.dart b/lib/components/permanent/overlay_tool_wrapper.dart index f915fdf..58ae5fd 100644 --- a/lib/components/permanent/overlay_tool_wrapper.dart +++ b/lib/components/permanent/overlay_tool_wrapper.dart @@ -7,6 +7,9 @@ import 'package:flutter_unit/components/permanent/circle.dart'; import 'package:flutter_unit/components/permanent/feedback_widget.dart'; import 'package:flutter_unit/views/pages/gallery/picture_frame.dart'; +import 'burst_flow.dart'; +import 'color_wrapper.dart'; + /// create by 张风捷特烈 on 2020/10/21 /// contact me by email 1981462002@qq.com /// 说明: @@ -56,8 +59,8 @@ class OverlayToolWrapperState extends State super.initState(); WidgetsBinding.instance.addPostFrameCallback((callback) { - var px = MediaQuery.of(context).size.width - (outWidth); - var py = 120.0; + var px = MediaQuery.of(context).size.width - 100; + var py = 40.0; offset = Offset(px, py); _ctrl = AnimationController( @@ -86,112 +89,143 @@ class OverlayToolWrapperState extends State entry.markNeedsBuild(); } - ///绘制悬浮控件 - _buildFloating() => Material( - color: Colors.transparent, - child: Row( - children: [ - GestureDetector( - onTap: () async { - if (out) { - close(); - } else { - open(); - } - }, - onPanUpdate: (DragUpdateDetails details) { - // offset = offset + details.delta; - double y = details.globalPosition.dy; - double x = details.globalPosition.dx; - if (y < 50) { - y = 50; - } - var px = MediaQuery.of(context).size.width - (outWidth); + final double circleRadius = 80; + final double menuSize = 36; - if (x < px - (width - outWidth)) { - x = px - (width - outWidth); - out = true; - } + GlobalKey burstFlowKey = GlobalKey(); - if (x > px) { - out = false; + _buildFloating() { + Color wrapColor = Colors.blue.withOpacity(0.6); - x = px; - } + bool left = offset.dx < 100; + print('-----left----${offset.dx}----'); - if (y > MediaQuery.of(context).size.height - 50) { - y = MediaQuery.of(context).size.height - 50; - } + return Container( + width: circleRadius * 2, + height: circleRadius * 2, + alignment: Alignment.center, + child: IconTheme( + data: IconTheme.of(context).copyWith(color: Colors.white, size: 18), + child: BurstFlow( + key:burstFlowKey, + startAngle: !left ? 90.0 + 15 : -90 + 15.0, + swapAngle: !left ? 180.0 - 15 * 2 : 180.0 - 15 * 2.0, + menu: GestureDetector( + onPanEnd: (details) { + double y = offset.dy; + double x = offset.dx; + + if (offset.dx > + MediaQuery.of(context).size.width / 2 - circleRadius) { + x = MediaQuery.of(context).size.width - + menuSize / 2 - + circleRadius; + } else { + x = menuSize / 2 - circleRadius; + } + + offset = Offset(x, y); + entry.markNeedsBuild(); + }, + onPanUpdate: (DragUpdateDetails details) { + double y = details.globalPosition.dy - circleRadius; + double x = details.globalPosition.dx - circleRadius; + if (x < menuSize / 2 - circleRadius) { + x = menuSize / 2 - circleRadius; + } + + if (y < menuSize / 2 - circleRadius) { + y = menuSize / 2 - circleRadius; + } + + if (x > + MediaQuery.of(context).size.width - + menuSize / 2 - + circleRadius) { + x = MediaQuery.of(context).size.width - + menuSize / 2 - + circleRadius; + } + + if (y > + MediaQuery.of(context).size.height - + menuSize / 2 - + circleRadius) { + y = MediaQuery.of(context).size.height - + menuSize / 2 - + circleRadius; + } + offset = Offset(x, y); + entry.markNeedsBuild(); + }, + child: Opacity( + opacity: 0.9, + child: Container( + width: menuSize, + height: menuSize, + padding: EdgeInsets.all(1.5), + decoration: BoxDecoration( + color: Colors.blue, + borderRadius: BorderRadius.circular(menuSize / 2)), - offset = Offset(x, y - boxHeight / 2); - entry.markNeedsBuild(); - }, - child: Opacity( - opacity: 0.7, child: Container( - width: outWidth, - height: outWidth, - padding: EdgeInsets.all(4), - child: Image.asset('assets/images/icon_head.webp'), decoration: BoxDecoration( - color: Theme.of(context).primaryColor, - boxShadow: [ - BoxShadow( - color: - Theme.of(context).primaryColor.withAlpha(128), - offset: Offset(.5, .5), - spreadRadius: .5, - blurRadius: .5) - ], - borderRadius: - BorderRadius.all(Radius.circular(outWidth / 2))), + color: Colors.blue, + image: DecorationImage( + image: AssetImage('assets/images/icon_head.webp')), + borderRadius: BorderRadius.circular(menuSize / 2)), ), - )), - PictureFrame( - alignment: Alignment.center, - marge: EdgeInsets.only(left: 8), - height: boxHeight, - width: width - outWidth + 15, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Wrap( - spacing: 10, - runSpacing: 10, - children: [ - buildItem(TolyIcon.icon_bug, () { - BlocProvider.of(context).add(EventLoadPoint()); - Navigator.of(context).pushNamed(UnitRouter.point); - }), - buildItem(Icons.palette, () { - Navigator.of(context).pushNamed(UnitRouter.galley); - }), - buildItem(Icons.widgets, () { - // Navigator.of(context).pushNamed(UnitRouter.galley); - }), - buildItem(TolyIcon.icon_tag, () { - // Navigator.of(context).pushNamed(UnitRouter.galley); - }), - buildItem(Icons.arrow_forward_outlined, () { - Scaffold.of(context).openDrawer(); - }), - buildItem(Icons.settings, () { - Navigator.of(context).pushNamed(UnitRouter.setting); - }), - buildItem(Icons.arrow_back, () { - Scaffold.of(context).openEndDrawer(); - }), - buildItem(Icons.close, () { - if (Navigator.of(context).canPop()) { - Navigator.of(context).pop(); - } - }), - ], ), ), ), - ], - ), - ); + children: [ + FeedbackWidget( + onPressed: () { + if (Navigator.of(context).canPop()) { + Navigator.of(context).pop(); + + + } + burstFlowKey.currentState.toggle(); + }, + child: Circled(color: wrapColor, child: Icon(Icons.close))), + FeedbackWidget( + onPressed: () { + BlocProvider.of(context).add(EventLoadPoint()); + Navigator.of(context).pushNamed(UnitRouter.point); + burstFlowKey.currentState.toggle(); + + }, + child: Circled( + color: wrapColor, + radius: 15, + child: Icon(TolyIcon.icon_bug))), + FeedbackWidget( + onPressed: () { + Navigator.of(context).pushNamed(UnitRouter.galley); + burstFlowKey.currentState.toggle(); + + }, + child: Circled( + color: wrapColor, + radius: 15, + child: Icon(Icons.palette))), + FeedbackWidget( + onPressed: () { + burstFlowKey.currentState.toggle(); + }, + child: Circled(color: wrapColor, child: Icon(Icons.widgets))), + FeedbackWidget( + onPressed: () { + Navigator.of(context).pushNamed(UnitRouter.setting); + burstFlowKey.currentState.toggle(); + + }, + child: Circled(color: wrapColor, child: Icon(Icons.settings))), + ]), + ), + ); + } Widget buildItem(IconData icon, Function onPress) { return FeedbackWidget(