Let’s start with the renderings
Implementation steps
Draw progress bar
- First draw the wave
void drawWave(Canvas canvas, Offset center, double radius,
double waveOffsetPercent, Paint paint) {
double waveOffset = -(waveOffsetPercent * radius * 2);
// Circle the canvascanvas.save(); Path clipPath = Path() .. addOval(Rect.fromCircle(center: center, radius: radius)); canvas.clipPath(clipPath);// Represent point(p) and controlPoint (C) as shown above
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);
// Complete the path linkPath 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();// Finish drawing
canvas.drawPath(wavePath, paint);
canvas.restore();
}
Copy the code
-
Draw a cascade of waves, using the same method as in the first step, by stagging the colors and offsets from the first wave
-
Draw the content of circular progress. What needs to be noted in this step is that the canvas needs to be rotated when drawing the progress. The specific content is as follows
Void drawCircleProgress(Canvas Canvas, Offset center, double radius, Size Size) {Canvas. DrawCircle (center, radius, circleProgressBGPaint); // Save the canvas state canvas.save(); 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); // Restore the canvas state canvas.restore(); }Copy the code
The drawing is almost done
Get the waves moving
Use animation to change the offset of the wave and make the animation repeat over and over again. The offset speeds of the two waves are set to be inconsistent to make the waves look more coordinated
void initState() {
super.initState();
waveAnimation = AnimationController(
vsync: this,
duration: widget.waveAnimationDuration,
);
waveAnimation.addListener(waveAnimationListener);
lightWaveAnimation = AnimationController(
vsync: this,
duration: widget.lightWaveAnimationDuration,
);
/ / for the latest wave in lightWaveAnimationListener offset value, refresh the status
lightWaveAnimation.addListener(lightWaveAnimationListener);
waveAnimation.repeat();
lightWaveAnimation.repeat();
}
Copy the code
After completing the effect of the wave moving, it is almost done, but there is an obvious problem, that is, after setting the progress, the wave in the progress bar will rise instantly, which looks very incongruous, so we need to add an animation effect for the progress bar when the progress changes.
Let the waves rise and fall slowly
@override
void initState() {
super.initState();
controller = AnimationController(
vsync: this, duration: widget.progressAnimatedDuration);
controller.addStatusListener((status) {
// Reset the animation when the animation ends
if(status == AnimationStatus.completed) { progressAnimation.removeListener(handleProgressChange); controller.reset(); }}); }@override
Widget build(BuildContext context) {
// Start animation when progress changes
if(currentValue ! = widget.value && ! controller.isAnimating) { progressAnimation = controller.drive(IntTween(begin: currentValue, end: widget.value)); progressAnimation.addListener(handleProgressChange); controller.forward(); }... }Copy the code
When the progress changes, we use an animation to change the progress to the specified progress, which ensures that the wave does not rise immediately when the progress changes.
The project address