Flutter中使用SpriteWidget循环切换独立图片实现类GIF动画
SpriteWidget 拆分单图实现逐帧循环动画
不需要提前合成精灵图,直接利用SpriteWidget自带的帧更新回调切换节点纹理就能实现,步骤如下:
- 首先把加载好的单帧图片按播放顺序整理成列表,避免每次切换都重复从ImageMap取资源
// 按播放顺序定义帧资源路径 const List<String> _frameAssetPaths = [ 'assets/image_0.png', 'assets/image_1.png', 'assets/image_2.png', ]; List<Image> _frameList = []; // 原有资源加载逻辑执行完后,按顺序组装帧列表 await images.load(_frameAssetPaths); _frameList = _frameAssetPaths.map((path) => images[path]!).toList();
- 自定义逐帧动画节点,继承Sprite基类,重写update方法处理计时和切帧逻辑
class SequenceFrameSprite extends Sprite { /// 按播放顺序排列的帧图片 final List<Image> frames; /// 单帧展示时长,单位秒 final double perFrameDuration; /// 是否循环播放 final bool loop; double _timeAccumulator = 0; int _currentIndex = 0; SequenceFrameSprite({ required this.frames, this.perFrameDuration = 0.5, this.loop = true, }) : super(frames.first) { // 初始展示第一帧 texture = SpriteTexture(frames.first); } @override void update(double dt) { super.update(dt); if (frames.length <= 1) return; _timeAccumulator += dt; // 累计时长达到单帧展示时长就切换 if (_timeAccumulator >= perFrameDuration) { _timeAccumulator = 0; _currentIndex++; // 处理循环/播放到末尾的逻辑 if (_currentIndex >= frames.length) { _currentIndex = loop ? 0 : frames.length - 1; } // 替换当前显示的纹理 texture = SpriteTexture(frames[_currentIndex]); } } /// 可选:重置动画到第一帧重头播放 void restart() { _timeAccumulator = 0; _currentIndex = 0; texture = SpriteTexture(frames.first); } }
- 最后在你的场景里初始化这个动画节点,加到SpriteWidget的节点树里即可
// 初始化动画节点,参数匹配需求:每帧展示0.5秒,循环播放 final gifLikeSprite = SequenceFrameSprite( frames: _frameList, perFrameDuration: 0.5, loop: true, ); // 按需设置位置、缩放、锚点等属性 gifLikeSprite.position = Offset(canvasSize.width / 2, canvasSize.height / 2); // 把节点添加到场景 addChild(gifLikeSprite);
补充说明:这种实现方式在帧数量不多(几十帧以内)的场景下,和精灵图方案的性能差异几乎可以忽略,完全满足常规动效需求。如果后续需要控制播放暂停,只要给
SequenceFrameSprite加个播放状态标记,在update方法里判断状态再累计时间即可,扩展很方便。
内容的提问来源于stack exchange,提问作者user3192190
相关产品推荐
相关产品推荐

