From e07df72ece62c370670ef7ad1137bd95a9b977f1 Mon Sep 17 00:00:00 2001 From: toly <1981462002@qq.com> Date: Thu, 8 Jul 2021 17:17:02 +0800 Subject: [PATCH] =?UTF-8?q?curve=20=E6=9F=A5=E7=9C=8B=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- android/key.properties | 4 + .../anim/curve_shower/anim_painter.dart | 2 +- .../anim/curve_shower/curve_anim_shower.dart | 83 +++++++- lib/painter_system/anim/draw_path.dart | 3 +- .../components/drop_selectable_widget.dart | 199 ++++++++++++++++++ 5 files changed, 279 insertions(+), 12 deletions(-) create mode 100644 lib/views/components/drop_selectable_widget.dart diff --git a/android/key.properties b/android/key.properties index e69de29..d66e87a 100644 --- a/android/key.properties +++ b/android/key.properties @@ -0,0 +1,4 @@ +#storePassword=toly1994 +#keyPassword=toly1994328 +#keyAlias= king +#storeFile=/Users/mac/Coder/files/key/toly1994.jks \ No newline at end of file diff --git a/lib/painter_system/anim/curve_shower/anim_painter.dart b/lib/painter_system/anim/curve_shower/anim_painter.dart index 85e394a..5df1ac1 100644 --- a/lib/painter_system/anim/curve_shower/anim_painter.dart +++ b/lib/painter_system/anim/curve_shower/anim_painter.dart @@ -73,7 +73,7 @@ class AnimPainter extends CustomPainter { if(points.values.length>0){ canvas.drawLine(Offset(0, -points.values.last*step*10), Offset(280, -points.values.last*step*10), Paint()..color=Colors.purple); - canvas.drawCircle(Offset(240, -points.values.last*step*10), 10, Paint()..color=Colors.orange); + canvas.drawCircle(Offset(230, -points.values.last*step*10), 10, Paint()..color=Colors.orange); } Path scalePath = Path(); diff --git a/lib/painter_system/anim/curve_shower/curve_anim_shower.dart b/lib/painter_system/anim/curve_shower/curve_anim_shower.dart index 69890c4..b1fda17 100644 --- a/lib/painter_system/anim/curve_shower/curve_anim_shower.dart +++ b/lib/painter_system/anim/curve_shower/curve_anim_shower.dart @@ -1,6 +1,7 @@ import 'dart:ui'; import 'package:flutter/material.dart'; +import 'package:flutter_unit/views/components/drop_selectable_widget.dart'; import 'anim_painter.dart'; import 'point_data.dart'; @@ -22,6 +23,50 @@ class _CurveAnimShowerState extends State Animation curveAnim; + Map maps = { + 'bounceOut': Curves.bounceOut, + 'linear': Curves.linear, + 'decelerate': Curves.decelerate, + 'fastLinearToSlowEaseIn': Curves.fastLinearToSlowEaseIn, + 'ease': Curves.ease, + 'easeIn': Curves.easeIn, + 'easeInToLinear': Curves.easeInToLinear, + 'easeInSine': Curves.easeInSine, + 'easeInQuad': Curves.easeInQuad, + 'easeInCubic': Curves.easeInCubic, + 'easeInQuart': Curves.easeInQuart, + 'easeInQuint': Curves.easeInQuint, + 'easeInExpo': Curves.easeInExpo, + 'easeInCirc': Curves.easeInCirc, + 'easeInBack': Curves.easeInBack, + 'easeOut': Curves.easeOut, + 'linearToEaseOut': Curves.linearToEaseOut, + 'easeOutSine': Curves.easeOutSine, + 'easeOutQuad': Curves.easeOutQuad, + 'easeOutCubic': Curves.easeOutCubic, + 'easeOutQuart': Curves.easeOutQuart, + 'easeOutQuint': Curves.easeOutQuint, + 'easeOutExpo': Curves.easeOutExpo, + 'easeOutCirc': Curves.easeOutCirc, + 'easeOutBack': Curves.easeOutBack, + 'easeInOut': Curves.easeInOut, + 'easeInOutSine': Curves.easeInOutSine, + 'easeInOutQuad': Curves.easeInOutQuad, + 'easeInOutCubic': Curves.easeInOutCubic, + 'easeInOutQuart': Curves.easeInOutQuart, + 'easeInOutExpo': Curves.easeInOutExpo, + 'easeInOutQuint': Curves.easeInOutQuint, + 'easeInOutCirc': Curves.easeInOutCirc, + 'easeInOutBack': Curves.easeInOutBack, + 'fastOutSlowIn': Curves.fastOutSlowIn, + 'slowMiddle': Curves.slowMiddle, + 'bounceIn': Curves.bounceIn, + 'bounceInOut': Curves.bounceInOut, + 'elasticIn': Curves.elasticIn, + 'elasticOut': Curves.elasticOut, + 'elasticInOut': Curves.elasticInOut, + }; + @override void initState() { super.initState(); @@ -52,15 +97,35 @@ class _CurveAnimShowerState extends State Widget build(BuildContext context) { return GestureDetector( onTap: _startAnim, - child: Padding( - padding: const EdgeInsets.all(30.0), - child: CustomPaint( - painter: AnimPainter(points), - size: const Size( - 200, - 200, - ), - ), + child: Stack( + alignment: Alignment.center, + children: [ + Positioned( + right: 5, + top: 5, + child: DropSelectableWidget( + fontSize: 12, + data: maps.keys.toList(), + iconSize: 20, + height: 25, + width: 180, + disableColor: Color(0xff1F425F), + onDropSelected: (int index) async { + curveAnim = CurvedAnimation( + parent: _ctrl, curve: maps.values.toList()[index]); + _startAnim(); + }, + )), + Padding( + padding: const EdgeInsets.all(30.0), + child: CustomPaint( + painter: AnimPainter(points), + size: const Size( + 200, + 200, + ), + )), + ], ), ); } diff --git a/lib/painter_system/anim/draw_path.dart b/lib/painter_system/anim/draw_path.dart index ab60b9a..682066c 100644 --- a/lib/painter_system/anim/draw_path.dart +++ b/lib/painter_system/anim/draw_path.dart @@ -23,8 +23,7 @@ class _DrawPathState extends State with SingleTickerProviderStateMixin _controller = AnimationController( duration: const Duration(seconds: 15), vsync: this, - )..repeat() - ; + )..repeat(); } @override diff --git a/lib/views/components/drop_selectable_widget.dart b/lib/views/components/drop_selectable_widget.dart new file mode 100644 index 0000000..799cf26 --- /dev/null +++ b/lib/views/components/drop_selectable_widget.dart @@ -0,0 +1,199 @@ +import 'dart:math'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +typedef OnDropSelected = void Function(int index); + +class DropSelectableWidget extends StatefulWidget { + final List data; + final OnDropSelected onDropSelected; + final Color disableColor; + final double iconSize; + final double height; + final double width; + final double fontSize; + + const DropSelectableWidget( + {Key key, + this.data = const [], + this.onDropSelected, + this.disableColor = Colors.black, + this.iconSize = 24, + this.height = 30, + this.width = 200, + this.fontSize = 14, + }) + : super(key: key); + + @override + _DropSelectableWidgetState createState() => _DropSelectableWidgetState(); +} + +class _DropSelectableWidgetState extends State + with SingleTickerProviderStateMixin { + FocusNode _node; + bool _focused = false; + FocusAttachment _nodeAttachment; + Color _color = Colors.white; + OverlayEntry _overlayEntry; + AnimationController _ctrl; + Animation animation; + final LayerLink layerLink = LayerLink(); + + int _selectedIndex = 0; + + @override + void initState() { + super.initState(); + + _ctrl = AnimationController( + vsync: this, + duration: const Duration(milliseconds: 200), + ); + + animation = Tween(begin: 0, end: pi).animate(_ctrl); + _node = FocusNode() + ..addListener(() { + if (_node.hasFocus != _focused) { + if (!_focused) { + _ctrl.forward(); + _showOverlay(); + } else { + _hideOverlay(); + _ctrl.reverse(); + } + setState(() { + _focused = _node.hasFocus; + }); + } + }); + _nodeAttachment = _node.attach(context); + } + + @override + void dispose() { + _node.dispose(); + _ctrl.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + _nodeAttachment.reparent(); + return GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + if (_focused) { + _node.unfocus(); + } else { + _node.requestFocus(); + } + }, + child: CompositedTransformTarget( + link: layerLink, + child: buildTarget(), + ), + ); + } + + void _showOverlay() { + _overlayEntry = _createOverlayEntry(); + Overlay.of(context).insert(_overlayEntry); + } + + void _hideOverlay() { + _overlayEntry?.remove(); + } + + Widget buildTarget() { + return Container( + width: widget.width, + height: widget.height, + padding: EdgeInsets.only(left: 10, right: 10), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + border: Border.all( + color: _focused ? Colors.blue : widget.disableColor, + )), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + '${widget.data.isNotEmpty ? widget.data[_selectedIndex] : "暂无数据"}',style: TextStyle( + height: 1, + fontSize: widget.fontSize + ),), + AnimatedBuilder( + animation: animation, + builder: (_, child) => Transform.rotate( + angle: animation.value, + child: child, + ), + child: Icon( + Icons.keyboard_arrow_down, + size: widget.iconSize, + ), + ), + ], + ), + ); + } + + OverlayEntry _createOverlayEntry() => OverlayEntry( + builder: (BuildContext context) => UnconstrainedBox( + child: CompositedTransformFollower( + link: layerLink, + targetAnchor: Alignment.bottomCenter, + followerAnchor: Alignment.topCenter, + child: Padding( + padding: const EdgeInsets.only(top: 4.0), + child: Material( + shape: RoundedRectangleBorder( + side: BorderSide.none, + borderRadius: BorderRadius.all(Radius.circular(5))), + elevation: 1, + child: ClipRRect( + borderRadius: BorderRadius.circular(5), + child: Container( + height: 200, + // alignment: Alignment.center, + decoration: BoxDecoration( + color: Color(0xffDAE3FF), + ), + // padding: const EdgeInsets.only(top: 5), + width: widget.width, + child: CupertinoScrollbar( + child: ListView.builder( + padding: EdgeInsets.zero, + // shrinkWrap: true, + itemCount: widget.data.length, + itemBuilder: _buildItem), + ), + ), + ), + ), + ), + ), + ), + ); + + Widget _buildItem(BuildContext context, int index) { + return Material( + child: InkWell( + onTap: () { + if (_selectedIndex != index) widget.onDropSelected?.call(index); + _selectedIndex = index; + _overlayEntry.markNeedsBuild(); + _node.unfocus(); + }, + child: Container( + padding: EdgeInsets.all(8), + color: index == _selectedIndex + ? Colors.blue.withOpacity(0.2) + : Colors.transparent, + child: Text('${widget.data[index]}',style: TextStyle(fontSize: widget.fontSize),)), + ), + ); + } +} \ No newline at end of file