前言
上节介绍了振幅相同曲线的波动实现,这一节我们介绍下效果图所示曲线的实现原理以及代码实现过程
- 首先要对需求有着确切的分析后,明确需求的大概实现思路,那么需求就已经实现了一半
分析
1.明确动画是不是有规律的?
- 确定是一个 振幅有规律递增递减的正弦函数,如果无规律则无法实现
2.曲线的函数表达式是什么?
- 正弦函数的表达式 y=A sin(ωx+φ), 振幅有规律递增递减的正弦函数是什么?,需要明确函数表达式
思路
- 通过确定曲线函数表达式,绘制递增递减的静态曲线
- 通过改变静态曲线的函数某些参数,实现曲线的波动
工欲善其事,必先利其器
推荐个工具,不仅更直观函数的图像表达,还可以设置参数调试动画效果
实在是居家旅行、杀 * 灭 *、必备良药
曲线的表达式
可惜数学都留在了校园,但曲线的形状感觉在哪里见到过,感觉像是信号与系统里的载波信号,经过上述工具的推算,最终表达式其实是两个正弦函数的乘积
- 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+φ)
的平移 是由φ
决定, 所以只需要控制funcSquaredSinx
中sin(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移动更消耗性能 但在接受范围之内
两种曲线的绘制方式
- 固定点的位置,固定路径绘制,移动画板canvas
- 刷新点的位置,不断重绘路径,生成动画
后续会将源码发布到github 或者做成插件发布到dart pub 上,敬请期待
扫描二维码关注公众号,回复: 13794027 查看本文章
未经作者授权,禁止转载