为了账号安全,请及时绑定邮箱和手机立即绑定

Flutter 119: 图解简易 ACEFrameAnimated 帧动画

标签:
Android

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

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

ACEFrameAnimated

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

enum ACEFramePicType { asset, network }

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

ACEFrameAnimated(this.picList, this.duration);

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

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 导致消息未返回;

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 中清空资源;

@override
void dispose() {
  super.dispose();
  if (_picList != null) {
    _picList.clear();
  }
  if (widget != null && widget.picList != null) {
    widget.picList.clear();
  }
}

    [ACEFrameAnimated 案例源码] github.com/ACE-YANGCE/FlutterApp/blob/master/lib/page/ace_frame_animated_page.dart


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

来源: 阿策小和尚

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
移动开发工程师
手记
粉丝
165
获赞与收藏
165

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消