Welcome to the original text:Tryenough.com/flutter-wav…
The effect
You can start with a quick understanding of how bezier curves work:
Recommend this tutorial on Bessel: www.html-js.com/article/162…
Code:
1. Create code to draw wave boundaries
Create a basic drawing class that accepts x and y values for animations:
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;
}
Copy the code
implementation
Welcome to the original text:Tryenough.com/flutter-wav…
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 = newPaint() .. 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 = newPath() .. 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 = newPaint() .. 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) {
returnoldDelegate ! =this; }}Copy the code
Welcome to the original text:Tryenough.com/flutter-wav…
2. Create factory method for creating wave graphics
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, ), ); }}Copy the code
Animate the waves
You are recommended to learn the basics of animation: juejin.cn/post/684490…
Principle explanation:
XAnimation and yAnimation constantly change from 0 to 1, and then the place where the wave is drawn is constantly drawn according to these values to form the animation.
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 =
newTween(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: newCustomPaint( 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(); }}Copy the code
Place of use
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ProgressManager(),
],
),
),
Copy the code
Welcome to the original text:Tryenough.com/flutter-wav…
Download demo address
Tryenough.com/flutter-wav…