Flutter 自定义动画在 OpenHarmony 手机上的性能优化实践
本文分享了在OpenHarmony设备上优化Flutter动画性能的实践经验。针对动画卡顿、GPU占用高等问题,作者提出多项优化措施:避免滥用AnimatedContainer,改用FadeTransition等轻量动画;正确管理AnimationController生命周期;缩小动画区域范围;使用RepaintBoundary隔离重绘;控制并发动画数量;优化列表动画实现。特别指出在OpenHar
欢迎加入开源鸿蒙跨平台社区:
https://openharmonycrossplatform.csdn.net
Flutter 自定义动画在 OpenHarmony 手机上的性能优化实践
前言
最近在做 Flutter for OpenHarmony 项目时,项目里加了不少动画效果。
包括:
- 首页 Banner 动画
- 卡片缩放
- 页面切换过渡
- 按钮点击反馈
- Loading 动画
刚开始在模拟器里看着还挺正常。
但真正放到 OpenHarmony 真机上之后,问题慢慢开始出现:
- 动画掉帧
- 页面发卡
- 滑动时动画不流畅
- GPU 占用偏高
- 多动画同时执行时明显卡顿
尤其是在一些中低端设备上,问题会更明显。
后面花了一段时间做动画性能优化,整体流畅度改善了很多。
这篇文章主要记录一下这次 Flutter 动画优化过程,以及我在 OpenHarmony 设备上踩过的一些坑。
一、最开始的动画实现
项目初期很多动画其实写得比较“直接”。
比如按钮点击缩放:
AnimatedContainer(
duration: const Duration(milliseconds: 300),
transform: Matrix4.identity()..scale(scale),
child: child,
)
或者:
AnimatedOpacity(
duration: const Duration(milliseconds: 300),
opacity: visible ? 1 : 0,
)
小页面问题不大。
但页面复杂后:
动画越来越多。
性能问题就开始明显了。
二、OpenHarmony 真机上的一个明显现象
这个是我最开始注意到的问题。
页面滑动 + 动画同时执行
例如:
商品列表滑动过程中:
顶部 Banner 同时自动轮播。
这时候会明显感觉:
- 滑动不跟手
- FPS 波动
- 动画偶发卡顿
Android 上也会有一点。
但 OpenHarmony 设备上更容易观察到。
尤其 GPU 曲线会明显升高。
三、不要滥用 AnimatedContainer
这个是我后面总结出来很重要的一点。
为什么
AnimatedContainer 虽然很好用。
但它本质上会触发:
- layout
- paint
- rebuild
如果页面里大量使用:
性能开销会比较明显。
后来的优化方案
简单透明度动画:
改成:
FadeTransition
位移动画:
改成:
SlideTransition
缩放动画:
使用:
ScaleTransition
相比 AnimatedContainer:
性能会稳定很多。
四、AnimationController 的正确使用
这里其实是 Flutter 动画里最核心的部分。
基础结构
class DemoPageState extends State<DemoPage>
with SingleTickerProviderStateMixin {
late AnimationController controller;
@override
void initState() {
super.initState();
controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 300),
);
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
}
一个我踩过的坑
刚开始有几个页面:
忘记 dispose。
结果:
页面退出后动画还在跑。
后面连续切页面:
CPU 占用越来越高。
在 OpenHarmony 真机上特别明显。
所以:
controller.dispose()
一定别忘。
五、减少动画区域重绘
这是这次优化里效果最明显的一部分。
问题
我之前很多动画直接包整个页面:
AnimatedBuilder(
animation: controller,
builder: (_, child) {
return Scaffold(
body: ...
);
},
)
结果:
动画执行时整个页面都在 repaint。
后来的优化
只让局部区域参与动画。
AnimatedBuilder(
animation: controller,
child: const GoodsCard(),
builder: (_, child) {
return Transform.scale(
scale: animation.value,
child: child,
);
},
)
这样:
child 不会重复 build。
性能会明显好很多。
六、RepaintBoundary 的实际效果
这个优化在鸿蒙设备上真的挺明显。
使用场景
例如:
- Banner
- 商品卡片
- 视频区域
- Loading 动画
这些复杂区域。
优化方式
RepaintBoundary(
child: BannerWidget(),
)
作用:
隔离重绘区域。
避免动画导致整个页面 repaint。
实际测试
优化前:
页面动画时:
GPU 曲线波动很明显。
优化后:
掉帧明显减少。
七、不要同时跑太多动画
这个问题我在首页踩得特别明显。
当时的首页
同时存在:
- Banner 自动轮播
- 卡片渐变
- 数字滚动
- 按钮缩放
- Loading 动画
模拟器没太大感觉。
真机上直接开始掉帧。
后来的处理
我做了几个优化:
1. 非必要动画直接删
有些动画纯装饰。
实际意义不大。
删掉后体验反而更稳定。
2. 控制动画时长
之前:
Duration(milliseconds: 1000)
太长。
后面统一:
200~300ms
会更自然。
3. 页面不可见时暂停动画
例如:
controller.stop()
页面返回时:
controller.forward()
这样能减少后台资源消耗。
八、列表动画是重灾区
这个我建议一定重点优化。
错误做法
列表每个 Item:
都加复杂动画。
ListView.builder(
itemBuilder: (_, index) {
return AnimatedContainer(
duration: Duration(milliseconds: 500),
);
},
)
数据量一大:
直接开始卡。
后来的方案
只对:
- 首屏
- 当前点击项
- 少量核心元素
做动画。
列表滚动性能会稳定很多。
九、OpenHarmony 下的一个特殊现象
这里是我这次适配里发现的一个细节。
问题现象
页面频繁 push/pop 后:
部分动画会偶发:
- 停止
- 卡死
- 不执行
Android 上复现概率低。
鸿蒙设备更容易出现。
后来的解决方式
我后来统一在:
didChangeDependencies()
里检查动画状态。
并且:
页面销毁时一定 dispose。
目前已经比较稳定。
十、如何观察动画性能
这个我建议一定开。
开启性能面板
MaterialApp(
showPerformanceOverlay: true,
)
重点观察:
- GPU 曲线
- UI 曲线
我的一些经验
GPU 高
通常是:
- repaint 太多
- 图片太大
- 动画区域太大
UI 高
通常是:
- build 太频繁
- 页面计算太重
- Widget 结构复杂
这个在 OpenHarmony 真机上挺有参考价值。
十一、优化前后效果
优化前:
| 问题 | 表现 |
|---|---|
| 动画掉帧 | 明显 |
| 页面卡顿 | 存在 |
| GPU 占用 | 偏高 |
| 列表动画 | 不流畅 |
优化后:
| 项目 | 效果 |
|---|---|
| 动画流畅度 | 提升明显 |
| 页面响应 | 更顺滑 |
| GPU 曲线 | 更稳定 |
| 多动画场景 | 基本正常 |
目前这套方案已经在项目里稳定运行了一段时间。
十二、总结
这次做 Flutter 动画优化,一个比较深的感受是:
Flutter 动画本身能力其实很强。
但如果:
- 动画区域太大
- rebuild 太频繁
- 多动画叠加
- 列表里乱加动画
性能问题会非常明显。
尤其在 OpenHarmony 真机环境里:
GPU 压力会比想象中更敏感。
我现在项目里的原则基本是:
- 能不用复杂动画就不用
- 动画只做局部
- 尽量减少 repaint
- 页面不可见时暂停动画
整体稳定性会好很多。
后面我还准备继续研究:
- Impeller 渲染器
- Flutter Shader 动画
- OpenHarmony GPU 渲染优化
- Flutter 游戏动画性能
希望这篇文章能给正在做 Flutter for OpenHarmony 开发的同学一点参考。
更多推荐

所有评论(0)