Flutter CustomPaint 绘制声音波动曲线(二)

voicewave.gif

前言

上节介绍了振幅相同曲线的波动实现,这一节我们介绍下效果图所示曲线的实现原理以及代码实现过程

  • 首先要对需求有着确切的分析后,明确需求的大概实现思路,那么需求就已经实现了一半

分析

1.明确动画是不是有规律的?

  • 确定是一个 振幅有规律递增递减的正弦函数,如果无规律则无法实现

2.曲线的函数表达式是什么?

  • 正弦函数的表达式 y=A sin(ωx+φ), 振幅有规律递增递减的正弦函数是什么?,需要明确函数表达式

思路

  1. 通过确定曲线函数表达式,绘制递增递减的静态曲线
  2. 通过改变静态曲线的函数某些参数,实现曲线的波动

工欲善其事,必先利其器

推荐个工具,不仅更直观函数的图像表达,还可以设置参数调试动画效果

实在是居家旅行、杀 * 灭 *、必备良药

曲线的表达式

可惜数学都留在了校园,但曲线的形状感觉在哪里见到过,感觉像是信号与系统里的载波信号,经过上述工具的推算,最终表达式其实是两个正弦函数的乘积

  • f(x) = A * sin(b * x) * sin(c * x)

曲线的绘制

 void paint(Canvas canvas, Size size) {
    // 获取采样点
    initPoints();
    // 画笔
    Paint paint = Paint()
      ..color = Colors.red
      ..strokeWidth = 2
      ..style = PaintingStyle.stroke;
    // 路径
    Path path = Path();
    canvas.translate(0, size.height / 2);
    // 通过点确定曲线路径
    for (var i = 1; i < xAliax.length - 1; i++) {
      double x1 = xAliax[i];
      double y1 = funcSquaredSinx(x1);
      double x2 = (xAliax[i] + xAliax[i + 1]) / 2;
      double y2 = (y1 + funcSquaredSinx(xAliax[i + 1])) / 2;
      path.quadraticBezierTo(x1, y1, x2, y2);
    }
    // 画布绘制
    canvas.drawPath(path, paint);
  }
复制代码
   //曲线函数表达式
   double funcSquaredSinx(double x) {
    double p = 30 * sin(3 * pi * x / 400) * sin(x * pi / 400);
    return p;
  }
复制代码
  • 采样点 [x1,x2,x3,....] 经过funcSquaredSinx 计算出y值
  • 通过path.quadraticBezierTo(x1, y1, x2, y2) 采样点相连接,最终绘制出曲线

曲线波动效果

首先需要思考一个问题,我们如何让曲线实现波动效果?

  • 振幅相同曲线通过canvas移动 实现曲线波动,在这里肯定不适应
  • 我们是采样点链接绘制路径,只有改变采样点的y值,需要从函数funcSquaredSinx入手

正弦函数 y=A sin(ωx+φ) 的平移 是由φ决定, 所以只需要控制funcSquaredSinxsin(3 * pi * x / 400 + φ)φ 便可以可以平移曲线。用工具演示如下

曲线波动的代码实现

  • 只需要我们传入 Animation *repaint 更改函数表达式
   Tween(begin: 0.0, end: 1.0).animate(_controller)
   //曲线函数表达式
   double funcSquaredSinx(double x) {
    double p = 
    30 * sin(3 * pi * x / 400 - 100 * repaint.value) * sin(x * pi / 400);
    return p;
  }
复制代码
  • 动画不断重绘,采样点的y值不断改变,路径不断改变,每一帧的路径渐变,产生动画
  • Canvas 可以绘制多条曲线,三条曲线初始相位不同和振幅不同,自定义每条线的粗细和颜色,便产生了首图的效果

总结

  • 优点
    • 任意曲线动效都能实现
    • 支持渐变色
  • 缺点
    • 不断重绘path,相对canvas移动更消耗性能 但在接受范围之内

两种曲线的绘制方式

  1. 固定点的位置,固定路径绘制,移动画板canvas
  2. 刷新点的位置,不断重绘路径,生成动画

后续会将源码发布到github 或者做成插件发布到dart pub 上,敬请期待

未经作者授权,禁止转载

猜你喜欢

转载自juejin.im/post/7043102653022224415