diff --git a/lib/painter_system/anim/spring_widget.dart b/lib/painter_system/anim/spring_widget.dart new file mode 100644 index 0000000..a4716ad --- /dev/null +++ b/lib/painter_system/anim/spring_widget.dart @@ -0,0 +1,134 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +class SpringWidget extends StatefulWidget { + + const SpringWidget(); + + @override + _SpringWidgetState createState() => _SpringWidgetState(); +} + +const double _kDefaultSpringHeight = 100; //弹簧默认高度 +const double _kRateOfMove = 1.5; //移动距离与形变量比值 + +const double _kK = 3; + +class _SpringWidgetState extends State with SingleTickerProviderStateMixin { + ValueNotifier height = ValueNotifier(_kDefaultSpringHeight); + + AnimationController _ctrl; + + double s = 0; // 移动距离 + double laseMoveLen = 0; + + Animation animation; + + final Duration animDuration = const Duration(milliseconds: 500); + + @override + void initState() { + super.initState(); + _ctrl = AnimationController(vsync: this, duration: animDuration) + ..addListener(_updateHeightByAnim); + // animation = CurvedAnimation(parent: _ctrl, curve: Curves.bounceOut); + animation = CurvedAnimation(parent: _ctrl, curve: const Interpolator()); + } + + void _updateHeightByAnim() { + s = laseMoveLen * (1 - animation.value); + height.value = _kDefaultSpringHeight + (-s / _kRateOfMove); + } + + @override + void dispose() { + _ctrl.dispose(); + height.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + onVerticalDragUpdate: _updateSpace, + onVerticalDragEnd: _animateToDefault, + child: Container( + width: 200, + height: 200, + color: Colors.grey.withAlpha(11), + child: CustomPaint( + painter: SpringPainter(height: height)), + ), + ); + } + + double f = 0; + + void _updateSpace(DragUpdateDetails details) { + s += details.delta.dy; + height.value = _kDefaultSpringHeight + dx; + } + + double get dx => -s / _kRateOfMove; + + double get k => _kK; + + void _animateToDefault(DragEndDetails details) { + // f = k * dx; + // print('----[弹性系数:$_kK]---[移动了:$dx]----[可提供弹力:$f]------------'); + laseMoveLen = s; + _ctrl.forward(from: 0); + } +} + +class Interpolator extends Curve { + const Interpolator(); + + @override + double transformInternal(double t) { + t -= 1.0; + return t * t * t * t * t + 1.0; + } +} + + +const double _kSpringWidth = 30; + +class SpringPainter extends CustomPainter { + final int count; + final ValueListenable height; + + SpringPainter({this.count = 20, this.height}):super(repaint: height); + + Paint _paint = Paint() + ..style = PaintingStyle.stroke + ..strokeWidth = 1; + + @override + void paint(Canvas canvas, Size size) { + canvas.translate(size.width / 2+_kSpringWidth / 2, size.height); + Path springPath = Path(); + springPath.relativeLineTo(-_kSpringWidth, 0); + double space = height.value/(count+1); + + for (int i = 1; i < count; i++) { + if (i % 2 == 1) { + springPath.relativeLineTo(_kSpringWidth, -space); + } else { + springPath.relativeLineTo(-_kSpringWidth, -space); + } + } + + if(count.isOdd){ + springPath.relativeLineTo(_kSpringWidth, 0); + }else{ + springPath.relativeLineTo(-_kSpringWidth, 0); + } + + canvas.drawPath(springPath, _paint); + } + + @override + bool shouldRepaint(covariant SpringPainter oldDelegate) => + oldDelegate.count != count || oldDelegate.height != height; +} diff --git a/lib/painter_system/gallery_factory.dart b/lib/painter_system/gallery_factory.dart index 4724c6f..678256e 100644 --- a/lib/painter_system/gallery_factory.dart +++ b/lib/painter_system/gallery_factory.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; +import 'package:flutter_unit/painter_system/anim/spring_widget.dart'; import 'anim/bezier3_player/bezier3_palyer.dart'; +import 'anim/draw_path.dart'; import 'art/circle_packing.dart'; import 'art/cubic_disarray.dart'; import 'art/hypnotic_squares.dart'; @@ -9,10 +11,9 @@ import 'art/piet_mondrian.dart'; import 'art/tiled_lines.dart'; import 'art/triangular_mesh.dart'; import 'art/un_deux_trois.dart'; -import 'anim/draw_path.dart'; import 'base/clock_widget.dart'; -import 'base/draw_path_fun.dart'; import 'base/draw_grid_axis.dart'; +import 'base/draw_path_fun.dart'; import 'base/draw_picture.dart'; import 'fun/random_portrait.dart'; import 'fun/stemp/stamp_paper.dart'; @@ -63,11 +64,22 @@ class GalleryFactory { ]; case GalleryType.anim: return [ + FrameShower( + title: "手势弹簧", + author: "张风捷特烈", + info: " 本样例介绍如何绘制弹簧,通过触点竖直拖拽拉伸、压缩,放手时进行恢复动画,是一个很好的综合小案例。", + content: const SpringWidget()), + FrameShower( + title: "Draw Curve", + author: "张风捷特烈", + info: " 本样例介绍如何使用路径绘制函数曲线,并使用路径测量进行动画", + content: DrawPath()), FrameShower( title: "Bezier3 演示 (双击清除)", author: "张风捷特烈", info: " 本样例介绍如何绘制三次贝塞尔曲线,通过触点判断某点是否激活,据此控制点的位置达到拖动控制效果。", - content: Bezier3Player()), FrameShower( + content: Bezier3Player()), + FrameShower( title: "Draw Curve", author: "张风捷特烈", info: " 本样例介绍如何使用路径绘制函数曲线,并使用路径测量进行动画", diff --git a/lib/views/pages/app/unit_navigation.dart b/lib/views/pages/app/unit_navigation.dart index e7929ab..1975b43 100644 --- a/lib/views/pages/app/unit_navigation.dart +++ b/lib/views/pages/app/unit_navigation.dart @@ -28,7 +28,6 @@ class _UnitNavigationState extends State { // 禁止 PageView 滑动 final ScrollPhysics neverScroll = const NeverScrollableScrollPhysics(); - @override void dispose() { _controller.dispose(); //释放控制器