//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小時內與您取得聯系。