Flutter实现弹幕热力图
产品提了个需求:播放器中增加弹幕热力图
问视觉小哥:曲线是怎么画出来的
视觉:用手画出来的
好像也没说错?是我高估了他的脚吗
最近 Flutter 使用得比之前熟练了一些,接了一个看起来比较有意思的需求:
一. 需求内容
在播放器中增加弹幕热力图组件 (在进度条上方绘制一条根据对应时间弹幕数量多少的有颜色曲线,并将其与进度条区域填充,已播放区域的颜色为激活态颜色)
二. 方案设计
前期的讨论与数据处理方式就不赘述了,结果是拿到最多50段时间对应的弹幕数,我们将其定义为关键点,也就说目前已经拿到了最多50个关键点的坐标,接下来说重点部分,也就是热力图的绘制,一开始想了三种实现方式:
- 引入第三方库
- 将曲线拆解到点的级别,每两个点连线
- 自定义View (CustomPaint)
关于引入第三方库的方式
- 发现了一个 flutter_chart 这个开源库,支持这样的现实效果,
- 接入过程中发现该库是针对静态图表设计的,进度动态变化的需求无法完成,且该库不支持曲线
- 该库功能庞大,引入会有很多无用代码
关于拆解到点级别的方式
- 将曲线拆解为像素,这样就都是直线
- 绘制曲线上每个像素点到底部进度条对应点的线即可
因为这种方式也有很明显的弊端:对性能开销较大,因此选用自定义 View 的方式
三. 实现过程
- Flutter也支持自定义 View,是通过 CustomPaint + 自定义画笔 Painter 来实现的(目前这类资料较少,这也是一开始考虑使用谷歌提供图表库的原因之一)
- 曲线通过关键点 + 三阶贝塞尔曲线、使用类似于差值器的思想完成
- 进度由播放器统一控制(即播放器控制进度条与热力图各自的进度)
0. 效果图
这里就不列出视觉稿了,实现效果如下,大概也就能理解需求是什么了吧
1. 曲线的绘制
我们知道贝塞尔曲线是一种比较优雅的曲线,这里为了节省时间,不和视觉小哥解释,直接使用三阶贝塞尔曲线
1 | /// 三阶贝塞尔曲线 |
2. 区域的填充
这里踩了个坑,一开始想的比较简单,想直接设置好路径、画笔将路径内区域填充,但是发现对于不规则形状的支持很差
然后再一次证明了“厕所是产生灵感的地方”,去了趟 wc 后突然想到可以直接将画布裁切、路径依旧设置为一个比画布区域大的规则图形、直接将其填充绘制,这样真实效果就会是将画布和路径的交集区域填充上颜色
1 | class HeatLineMonet { |
搞定
PS 这里只列举出比较关键的代码,不是全部