forked from lxm_flutter/FlutterUnit
绘制集录-手势弹簧
This commit is contained in:
134
lib/painter_system/anim/spring_widget.dart
Normal file
134
lib/painter_system/anim/spring_widget.dart
Normal file
@@ -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<SpringWidget> with SingleTickerProviderStateMixin {
|
||||
ValueNotifier<double> height = ValueNotifier(_kDefaultSpringHeight);
|
||||
|
||||
AnimationController _ctrl;
|
||||
|
||||
double s = 0; // 移动距离
|
||||
double laseMoveLen = 0;
|
||||
|
||||
Animation<double> 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<double> 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;
|
||||
}
|
||||
@@ -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: " 本样例介绍如何使用路径绘制函数曲线,并使用路径测量进行动画",
|
||||
|
||||
@@ -28,7 +28,6 @@ class _UnitNavigationState extends State<UnitNavigation> {
|
||||
// 禁止 PageView 滑动
|
||||
final ScrollPhysics neverScroll = const NeverScrollableScrollPhysics();
|
||||
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose(); //释放控制器
|
||||
|
||||
Reference in New Issue
Block a user