//html code
<div class="ripple" title="谢谢点赞~~">
<span>2021</span>
</div>缺少@types/node模块所致。该模块用于提供Node.js类型定义的模块,使开发者在编写Node.js代码时获得更好的代码补全和类型检查支持。
开启Node.js编码协助
如果报错无法下载 @types/node No @types/node versions available,可用方案2或3。
全局安装 @types/node 包:
npm install @types/node -g在 Windows 系统中,全局安装的 node_modules 目录路径通常位于 C:\Users\{用户名}\AppData\Roaming\npm\node_modules。
在Webstorm点击设置,选择语言和框架->JavaScript->库,指定文件夹为C:\Users\Administrator\AppData\Roaming\npm\node_modules\@types。
在项目中局部安装@types/node模块:
npm install @types/node --save-dev迎去浏览原文:http://tryenough.com/flutter-wave
效果
你可以先简单理解下贝塞尔曲线的原理:
推荐这个关于贝塞尔的教程:http://www.html-js.com/article/1628
代码:
1.创建绘制波浪边界的代码
创建一个基础的绘制类,可接收动画的x和y值:
import 'package:flutter/material.dart';
abstract class BasePainter extends CustomPainter{
Animation<double> _xAnimation;
Animation<double> _yAnimation;
set XAnimation(Animation<double> value) {
_xAnimation=value;
}
set YAnimation(Animation<double> value) {
_yAnimation=value;
}
Animation<double> get YAnimation=> _yAnimation;
Animation<double> get XAnimation=> _xAnimation;
}
实现
欢迎去浏览原文:http://tryenough.com/flutter-wave
import 'dart:math';
import 'package:flutter_wave/painter_base.dart';
import 'package:flutter/material.dart';
class WavePainter extends BasePainter {
int waveCount;
int crestCount;
double waveHeight;
List<Color> waveColors;
double circleWidth;
Color circleColor;
Color circleBackgroundColor;
bool showProgressText;
TextStyle textStyle;
WavePainter(
{this.waveCount=1,
this.crestCount=2,
this.waveHeight,
this.waveColors,
this.circleColor=Colors.grey,
this.circleBackgroundColor=Colors.white,
this.circleWidth=5.0,
this.showProgressText=true,
this.textStyle=const TextStyle(
fontSize: 60.0,
color: Colors.blue,
fontWeight: FontWeight.bold,
shadows: [
Shadow(color: Colors.grey, offset: Offset(5.0, 5.0), blurRadius: 5.0)
],
)});
@override
void paint(Canvas canvas, Size size) {
double width=size.width;
double height=size.height;
if (waveHeight==null) {
waveHeight=height / 10;
height=height + waveHeight;
}
if (waveColors==null) {
waveColors=[
Color.fromARGB(
100, Colors.blue.red, Colors.blue.green, Colors.blue.blue)
];
}
Offset center=new Offset(width / 2, height / 2);
double xMove=width * XAnimation.value;
double yAnimValue=0.0;
if (YAnimation !=null) {
yAnimValue=YAnimation.value;
}
double yMove=height * (1.0 - yAnimValue);
Offset waveCenter=new Offset(xMove, yMove);
var paintCircle=new Paint()
..color=Colors.grey
..style=PaintingStyle.fill
..strokeWidth=circleWidth
..maskFilter=MaskFilter.blur(BlurStyle.inner, 5.0);
// canvas.drawCircle(center, min(width, height) / 2, paintCircle);
List<Path> wavePaths=[];
for (int index=0; index < waveCount; index++) {
double direction=pow(-1.0, index);
Path path=new Path()
..moveTo(waveCenter.dx - width, waveCenter.dy)
..lineTo(waveCenter.dx - width, center.dy + height / 2)
..lineTo(waveCenter.dx + width, center.dy + height / 2)
..lineTo(waveCenter.dx + width, waveCenter.dy);
for (int i=0; i < 2; i++) {
for (int j=0; j < crestCount; j++) {
double a=pow(-1.0, j);
path
..quadraticBezierTo(
waveCenter.dx +
width * (1 - i - (1 + 2 * j) / (2 * crestCount)),
waveCenter.dy + waveHeight * a * direction,
waveCenter.dx +
width * (1 - i - (2 + 2 * j) / (2 * crestCount)),
waveCenter.dy);
}
}
path..close();
wavePaths.add(path);
}
var paint=new Paint()
..color=circleBackgroundColor
..style=PaintingStyle.fill
..maskFilter=MaskFilter.blur(BlurStyle.inner, 5.0);
canvas.saveLayer(
Rect.fromCircle(center: center, radius: min(width, height) / 2), paint);
// canvas.drawCircle(center, min(width, height) / 2, paint);
paint
// ..blendMode=BlendMode.srcATop
..style=PaintingStyle.fill
..strokeWidth=2.0
..maskFilter=MaskFilter.blur(BlurStyle.inner, 10.0);
for (int i=0; i < wavePaths.length; i++) {
if (waveColors.length >=wavePaths.length) {
paint.color=waveColors[i];
} else {
paint.color=waveColors[0];
}
canvas.drawPath(wavePaths[i], paint);
}
// paint.blendMode=BlendMode.srcATop;
if (showProgressText) {
TextPainter tp=TextPainter(
text: TextSpan(
text: '${(yAnimValue * 100.0).toStringAsFixed(0)}%',
style: textStyle),
textDirection: TextDirection.rtl)
..layout();
tp.paint(
canvas, Offset(center.dx - tp.width / 2, center.dy - tp.height / 2));
}
canvas.restore();
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return oldDelegate !=this;
}
}
欢迎去浏览原文:http://tryenough.com/flutter-wave
2.创建工厂方法,用于创建波浪图形
import 'package:flutter/material.dart';
import 'package:flutter_wave/painter_base.dart';
import 'package:flutter_wave/painter/painter_wave.dart';
abstract class BasePainterFactory {
BasePainter getPainter();
}
class WavePainterFactory extends BasePainterFactory {
BasePainter getPainter() {
return WavePainter(
waveCount: 1,
waveColors: [
Colors.lightBlueAccent[200],
],
textStyle:
TextStyle(
fontSize: 60.0,
foreground: Paint()
..color=Colors.lightBlue
..style=PaintingStyle.fill
..strokeWidth=2.0
..blendMode=BlendMode.difference
..colorFilter=ColorFilter.mode(Colors.white, BlendMode.exclusion)
..maskFilter=MaskFilter.blur(BlurStyle.solid, 1.0),
fontWeight: FontWeight.bold,
),
);
}
}
给波浪添加动画
推荐你先学一下动画基础知识:
https://juejin.im/post/5b6270edf265da0f473539a6
原理解释:
xAnimation和yAnimation不断的从0到1变化,然后上面绘制波浪的地方根据这些值不断的进行绘制,形成动画。
import 'package:flutter_wave/painter_factory.dart';
import 'package:flutter/material.dart';
class ProgressManager extends StatefulWidget {
@override
_ProgressManagerState createState()=>
new _ProgressManagerState().._factory=WavePainterFactory();
}
class _ProgressManagerState extends State<ProgressManager>
with TickerProviderStateMixin {
AnimationController xController;
AnimationController yController;
Animation<double> xAnimation;
Animation<double> yAnimation;
List<double> _progressList=[];
double curProgress=0;
BasePainterFactory _factory;
set painter(BasePainterFactory factory) {
_factory=factory;
}
setProgress(double progress) {
_progressList.add(progress);
onProgressChange();
}
onProgressChange() {
if (_progressList.length > 0) {
if (yController !=null && yController.isAnimating) {
return;
}
double nextProgress=_progressList[0];
_progressList.removeAt(0);
final double begin=curProgress;
yController=new AnimationController(
vsync: this, duration: Duration(milliseconds: 1000));
yAnimation=new Tween(begin: begin, end: nextProgress).animate(yController);
yAnimation.addListener(_onProgressChange);
yAnimation.addStatusListener(_onProgressStatusChange);
yController.forward();
}
}
@override
void initState() {
super.initState();
xController=new AnimationController(
vsync: this, duration: Duration(milliseconds: 4000));
xAnimation=new Tween(begin: 0.0, end: 1.0).animate(xController);
xAnimation.addListener(_change);
yController=new AnimationController(
vsync: this, duration: Duration(milliseconds: 5000));
yAnimation=new Tween(begin: 0.0, end: 1.0).animate(yController);
yAnimation.addListener(_onProgressChange);
yAnimation.addStatusListener(_onProgressStatusChange);
doDelay(xController, 0);
Future.delayed(Duration(milliseconds: 3000), () {
setProgress(0.66);
});
}
@override
Widget build(BuildContext context) {
return Center(
child:
Container(
width: MediaQuery.of(context).size.width,
height: 400.0,
child: new CustomPaint(
painter: _factory.getPainter()
..XAnimation=xAnimation
..YAnimation=yAnimation,
size: new Size(MediaQuery.of(context).size.width, 400.0),
),
),
);
}
void _change() {
setState(() {});
}
void _onProgressChange() {
setState(() {
curProgress=yAnimation.value;
});
}
void _onProgressStatusChange(status) {
if (status==AnimationStatus.completed) {
onProgressChange();
}
}
void doDelay(AnimationController controller, int delay) async {
Future.delayed(Duration(milliseconds: delay), () {
controller..repeat();
});
}
@override
void dispose() {
xController.dispose();
yController.dispose();
xAnimation.removeListener(_change);
yAnimation.removeListener(_onProgressChange);
yAnimation.removeStatusListener(_onProgressStatusChange);
super.dispose();
}
}
使用的地方
body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ ProgressManager(), ], ), ),
欢迎去浏览原文:http://tryenough.com/flutter-wave
下载demo地址
http://tryenough.com/flutter-wave
*请认真填写需求信息,我们会在24小时内与您取得联系。