ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Lottie、Rive 与 CustomPainter,要按交互路径选

2026/8/14 16:15:04 拓冰建站 浏览量
Lottie、Rive 与 CustomPainter,要按交互路径选 Lottie、Rive 与 CustomPainter要按交互路径选Lottie、Rive 和CustomPainter解决的不是同一类问题。先问动画是否需要交互状态机、资源有多复杂、它出现在哪条用户路径再看工具功能清单只能初筛。复杂矢量资源可能带来较高的解析、绘制或缓存成本具体表现与 Flutter 版本、渲染后端和资源内容有关不应预设某一方案一定更快。真机轨迹要覆盖首次播放在目标设备用 Profile 模式抓取轨迹先区分 build、raster 和资源解码等问题。# 启动渲染管线性能指标监测捕获 Skia/Impeller 着色器编译耗时 flutter run --profile --trace-skia --trace-systrace # 查看当前设备显存与 Flutter Raster 线程占用 flutter driver --targettest_driver/perf_test.dart --profile如果轨迹显示首次播放或特定资源导致 raster 时间上升检查矢量路径、蒙版、混合模式和资源尺寸。不要仅凭动画格式判断原因。动画选型决策与渲染管线分流可以按交互复杂度、资源复杂度和设备表现建立简单的选型路径CustomPainter 与 Rive 状态机封装示例列表中的简单高频绘制可以用CustomPainter控制绘制范围。以下组件演示一个波浪进度效果它仍需结合实际设备检查耗时import dart:math as math; import package:flutter/material.dart; /// 使用 CustomPainter 纯代码绘制零着色器编译开销的波浪粒子 class PureCanvasWaveProgress extends StatefulWidget { final double progress; // 0.0 ~ 1.0 const PureCanvasWaveProgress({Key? key, required this.progress}) : super(key: key); override StatePureCanvasWaveProgress createState() _PureCanvasWaveProgressState(); } class _PureCanvasWaveProgressState extends StatePureCanvasWaveProgress with SingleTickerProviderStateMixin { late final AnimationController _animController; override void initState() { super.initState(); _animController AnimationController( vsync: this, duration: const Duration(milliseconds: 2000), )..repeat(); } override void dispose() { _animController.dispose(); super.dispose(); } override Widget build(BuildContext context) { return AnimatedBuilder( animation: _animController, builder: (context, _) { return CustomPaint( size: const Size(200, 200), painter: WavePainter( animationValue: _animController.value, progress: widget.progress, ), ); }, ); } } class WavePainter extends CustomPainter { final double animationValue; final double progress; WavePainter({required this.animationValue, required this.progress}); override void paint(Canvas canvas, Size size) { final paint Paint() ..color Colors.blue.withOpacity(0.6) ..style PaintingStyle.fill; final path Path(); final waveHeight 8.0; final waveWidth size.width; final dy size.height * (1 - progress); path.moveTo(0, dy); for (double x 0; x waveWidth; x) { // 纯数学正弦曲线计算无需昂贵的矢量蒙版 final y dy math.sin((x / waveWidth * 2 * math.pi) (animationValue * 2 * math.pi)) * waveHeight; path.lineTo(x, y); } path.lineTo(size.width, size.height); path.lineTo(0, size.height); path.close(); canvas.drawPath(path, paint); } override bool shouldRepaint(covariant WavePainter oldDelegate) { return oldDelegate.animationValue ! animationValue || oldDelegate.progress ! progress; } }选型时容易漏看的三个指标动画选型除了设计还原度也应评估以下指标观察首次播放和重复播放的 raster 时间。复杂路径或混合模式可能需要简化资源或调整展示时机。资源体积、解码后的内存和缓存策略应一起测量不要用不同格式之间的固定倍数作判断。在项目实际使用的渲染后端和系统版本上验收视觉效果尤其是混合模式、蒙版与透明度叠加。选型结论高频微交互优先选择可控、易测的实现复杂叙事动画再按资源与状态需求选工具。无论最后用哪一个都回到覆盖真机看性能轨迹和视觉结果。