首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【Flutter 专题】119 图解简易 ACEFrameAnimated 帧动画

【Flutter 专题】119 图解简易 ACEFrameAnimated 帧动画

作者头像
阿策小和尚
发布2021-04-22 15:24:46
发布2021-04-22 15:24:46
1K0
举报
文章被收录于专栏:阿策小和尚阿策小和尚

和尚在做 Android 开发时,常常需要 帧动画 来作为作为 loading 动画;而 Flutter 没有直接提供类似于 帧动画 的组件,和尚简单尝试一个简单的 ACEFrameAnimated 帧动画小组件;

和尚理解的 帧动画 其实一系列图片在一段时间内的叠加展示,以达到连贯的动画效果;

ACEFrameAnimated

和尚认为,帧动画最重要的两个元素,分别是图片资源和间隔时间;之后便可对图片根据间隔时间来循环展示;为了适配网络图片和本地图片,和尚设置了一个 ACEFramePicType 资源类型;

代码语言:javascript
复制
enum ACEFramePicType { asset, network }

final List<Map<ACEFramePicType, String>> picList;
final Duration duration;

ACEFrameAnimated(this.picList, this.duration);

和尚计划返回一个基本的 Widget,并通过 Future 延迟加载图片资源,其中需要注意的是循环加载,注意当前数组下标;其中在 initState() 中更新图片 _framePicList() 时,需要在 Future.delayed 之前先加载第一张图片,否则会出现短暂空白的情况;

代码语言:javascript
复制
class _ACEFrameAnimatedState extends State<ACEFrameAnimated> {
  List<Map<ACEFramePicType, String>> _picList;
  Duration _duration;
  int _index = 0;
  Widget _buildWid = Container();

  _ACEFrameAnimatedState(this._picList, this._duration);

  @override
  void initState() {
    super.initState();
    _framePicList();
  }

  @override
  Widget build(BuildContext context) => _buildWid;

  _framePicList() async {
    setState(() {
      _index = _index % _picList.length;
      _buildWid = Container(
          child: _picList[_index].keys.toList()[0] == ACEFramePicType.asset
              ? Image.asset(_picList[_index].values.toList()[0])
              : Image.network(_picList[_index].values.toList()[0]));
      _index++;
    });
    await Future.delayed(_duration, () => _framePicList());
  }
}

Tips

和尚在退出页面时出现内存溢出,导致原因有两个,第一个是未清除 Widget 中的资源列表;第二个是 Future.delayed 发送消息后,await 导致消息未返回;

代码语言:javascript
复制
E/flutter (13298): This error happens if you call setState() on a State object for a widget that no longer appears in the widget tree (e.g., whose parent widget no longer includes the widget in its build). This error can occur when code calls setState() from a timer or an animation callback.
E/flutter (13298): The preferred solution is to cancel the timer or stop listening to the animation in the dispose() callback. Another solution is to check the "mounted" property of this object before calling setState() to ensure the object is still in the tree.
E/flutter (13298): This error might indicate a memory leak if setState() is being called because another object is retaining a reference to this State object after it has been removed from the tree. To avoid memory leaks, consider breaking the reference to this object during dispose().
E/flutter (13298): #0      State.setState.<anonymous closure> (package:flutter/src/widgets/framework.dart:1112:9)
E/flutter (13298): #1      State.setState (package:flutter/src/widgets/framework.dart:1147:6)
E/flutter (13298): #2      _ACEFrameAnimatedState._framePicList (package:flutter_app/widget/ace_frame_animated.dart:32:5)
E/flutter (13298): #3      _ACEFrameAnimatedState._framePicList.<anonymous closure> (package:flutter_app/widget/ace_frame_animated.dart:40:43)
E/flutter (13298): #4      new Future.delayed.<anonymous closure> (dart:async/future.dart:316:39)
E/flutter (13298): #5      _rootRun (dart:async/zone.dart:1122:38)
E/flutter (13298): #6      _CustomZone.run (dart:async/zone.dart:1023:19)
E/flutter (13298): #7      _CustomZone.runGuarded (dart:async/zone.dart:925:7)
E/flutter (13298): #8      _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:965:23)
E/flutter (13298): #9      _rootRun (dart:async/zone.dart:1126:13)
E/flutter (13298): #10     _CustomZone.run (dart:async/zone.dart:1023:19)
E/flutter (13298): #11     _CustomZone.bindCallback.<anonymous closure> (dart:async/zone.dart:949:23)
E/flutter (13298): #12     Timer._createTimer.<anonymous closure> (dart:async-patch/timer_patch.dart:23:15)
E/flutter (13298): #13     _Timer._runTimers (dart:isolate-patch/timer_impl.dart:384:19)
E/flutter (13298): #14     _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:418:5)
E/flutter (13298): #15     _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:174:12)

和尚根据提示在使用 setState 时先判断当前 State 是否已绑定在 View 中;同时在 dispose 中清空资源;

代码语言:javascript
复制
@override
void dispose() {
  super.dispose();
  if (_picList != null) {
    _picList.clear();
  }
  if (widget != null && widget.picList != null) {
    widget.picList.clear();
  }
}

ACEFrameAnimated 案例源码


和尚仅实现了最基本的帧动画效果,对于效果的优化还未涉及;如有错误请多多指导!

来源:阿策小和尚

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-03-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 阿策小和尚 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ACEFrameAnimated
  • Tips
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档