先上效果图git
先绘制绘制波浪github
void drawWave(Canvas canvas, Offset center, double radius,
double waveOffsetPercent, Paint paint) {
double waveOffset = -(waveOffsetPercent * radius * 2);
//对画布进行圆形裁剪
canvas.save();
Path clipPath = Path()
..addOval(Rect.fromCircle(center: center, radius: radius));
canvas.clipPath(clipPath);
//表示出上图所示的point(上图中p)以及controlPoint(上图中c)
double waveProgressHeightY = (1 - percent) * radius * 2;
Offset point1 = Offset(waveOffset, waveProgressHeightY);
Offset point2 = Offset(waveOffset + radius, waveProgressHeightY);
Offset point3 = Offset(waveOffset + radius * 2, waveProgressHeightY);
Offset point4 = Offset(waveOffset + radius * 3, waveProgressHeightY);
Offset point5 = Offset(waveOffset + radius * 4, waveProgressHeightY);
Offset point6 = Offset(point5.dx, radius * 2 + halfWaveHeight);
Offset point7 = Offset(point1.dx, radius * 2 + halfWaveHeight);
Offset controlPoint1 =
Offset(waveOffset + radius * 0.5, waveProgressHeightY - halfWaveHeight);
Offset controlPoint2 =
Offset(waveOffset + radius * 1.5, waveProgressHeightY + halfWaveHeight);
Offset controlPoint3 =
Offset(waveOffset + radius * 2.5, waveProgressHeightY - halfWaveHeight);
Offset controlPoint4 =
Offset(waveOffset + radius * 3.5, waveProgressHeightY + halfWaveHeight);
//完成path的连接
Path wavePath = Path()
..moveTo(point1.dx, point1.dy)
..quadraticBezierTo(
controlPoint1.dx, controlPoint1.dy, point2.dx, point2.dy)
..quadraticBezierTo(
controlPoint2.dx, controlPoint2.dy, point3.dx, point3.dy)
..quadraticBezierTo(
controlPoint3.dx, controlPoint3.dy, point4.dx, point4.dy)
..quadraticBezierTo(
controlPoint4.dx, controlPoint4.dy, point5.dx, point5.dy)
..lineTo(point6.dx, point6.dy)
..lineTo(point7.dx, point7.dy)
..close();
//完成绘制
canvas.drawPath(wavePath, paint);
canvas.restore();
}
复制代码
绘制层叠的波浪,跟第一步同样的绘制方法,能够将颜色与偏移值跟第一个波浪错开canvas
绘制圆形进度内容,这一步须要注意的是在绘制进度的时候,须要对画布进行旋转,具体绘制内容以下ide
void drawCircleProgress(
Canvas canvas,
Offset center,
double radius,
Size size) {
//画进度条圆框背景
canvas.drawCircle(center, radius, circleProgressBGPaint);
//保存画布状态
canvas.save();
//逆时针旋转画布90度
canvas.rotate(degreeToRadian(-90));
canvas.translate(
-(size.height + size.width) / 2, -(size.height - size.width) / 2);
//画进度条圆框进度
canvas.drawArc(
Rect.fromCircle(center: center, radius: radius),
degreeToRadian(0),
degreeToRadian(percent * 360),
false,
circleProgressPaint);
//恢复画布状态
canvas.restore();
}
复制代码
绘制工做基本就差很少完成了动画
利用动画更改波浪的偏移值,并使动画不停的进行重复。两个波浪偏移的速度设置成不一致的,让波浪看起来更协调ui
void initState() {
super.initState();
waveAnimation = AnimationController(
vsync: this,
duration: widget.waveAnimationDuration,
);
waveAnimation.addListener(waveAnimationListener);
lightWaveAnimation = AnimationController(
vsync: this,
duration: widget.lightWaveAnimationDuration,
);
//在lightWaveAnimationListener中获取波浪最新的偏移值,刷新状态
lightWaveAnimation.addListener(lightWaveAnimationListener);
waveAnimation.repeat();
lightWaveAnimation.repeat();
}
复制代码
完成波浪动起来的效果以后基本上就差很少了,可是会有一个很明显的问题,那就是在设置进度以后,进度条中的波浪是瞬间涨上去,看上去很是的不协调,因此咱们还须要给进度条加上一个,进度更改时的动画效果。this
@override
void initState() {
super.initState();
controller = AnimationController(
vsync: this, duration: widget.progressAnimatedDuration);
controller.addStatusListener((status) {
//当动画结束时重置动画
if (status == AnimationStatus.completed) {
progressAnimation.removeListener(handleProgressChange);
controller.reset();
}
});
}
@override
Widget build(BuildContext context) {
//当进度发生改变时,开始动画
if (currentValue != widget.value && !controller.isAnimating) {
progressAnimation =
controller.drive(IntTween(begin: currentValue, end: widget.value));
progressAnimation.addListener(handleProgressChange);
controller.forward();
}
...
}
复制代码
在进度改变时,咱们经过一个动画来改变进度到指定的进度,这样就保证了,进度发生改变时,波浪不会瞬间涨上去。spa
项目地址rest