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…