Flutter 134: 图解动画小插曲之 SVGA 动画

    小菜之前尝试了 FlareLottie 动画,实现效果都很高效;今天小菜尝试另一种思路 SVGA 动画;SVGA 是一种同时兼容 iOS / Android / Flutter / Web 多个平台的动画格式;

SVGA

基本简介

    小菜首先赞美一下 SVGA 官网,非常简洁而且主要信息都容易查到,同时看着非常舒服;设计师通过 AE 等工具设计生成好 SVGA 动画后,可直接交付给开发同学通过 SVGAPlayer 直接调用即可,集成和应用都很简单;

    SVGA 提供了在线动画素材预览以及素材元素拆分,还可以将 SVGA 动画转化为 SVG 矢量图元素,非常灵活方便;

案例尝试

    SVGA 提供了多种方式完整的集成方案,小菜简单尝试一下 Flutter 版本应用;

1. 集成 svgaplayer_flutter

    与所有插件使用相同,小菜引入对应版本的 svgaplayer_flutter;目前 svgaplayer_flutter 已支持 Flutter 2.0 空安全;

svgaplayer_flutter: ^2.1.2

2. 应用播放 SVGA

2.1 SVGASimpleImage 加载动画

    svgaplayer_flutter 支持播放本地动画和网络线上动画,与 Image 加载本地和网络图片类似;SVGA 提供了封装好 SVGAAnimationController 控制器的 SVGASimpleImage;根据文件类型,通过不同参数进行展示,默认动画效果为重复播放;

class SVGASimpleImage extends StatefulWidget {
  final String resUrl;
  final String assetsName;
  final File file;

  SVGASimpleImage({Key key, this.resUrl, this.assetsName, this.file}) : super(key: key);

  @override
  State<StatefulWidget> createState() => _SVGASimpleImageState();
}

    简单分析源码可得,SVGASimpleImage 根据传递的不同动画路径进行不同方式的展示,通过 SVGAParser.shared 加载和解码不同类型的网络资源、本地资源以及 File 资源等;

class _SVGAPageState extends State<SVGAPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: Text('SVGA Page')),
        body: Column(children: [
          _itemSVGA01(false, 'images/posche.svga'),
          _itemSVGA01(true, 'https://github.com/yyued/SVGA-Samples/blob/master/angel.svga?raw=true')
        ]));
  }

  _itemSVGA01(isUrl, svgaUrl) {
    return Expanded( flex: 1,
        child: SVGASimpleImage(assetsName: isUrl ? null : svgaUrl, resUrl: isUrl ? svgaUrl : null));
  }
}
2.2 SVGAImage & SVGAAnimationController

    SVGASimpleImage 是将 SVGAImageSVGAAnimationController 封装好的动画播放器,若我们想自由控制动画的播放、暂停、重播等操作的话,需要配合 SVGAAnimationController 控制器调节动画的播放过程;

SVGAImage(
    this._controller, {
    this.fit = BoxFit.contain,
    this.clearsAfterStop = true,
})

    简单分析源码可得,SVGAImage 主要是通过 SVGAAnimationController 来进行动画播放;与图片类似,可以通过 BoxFit 设置动画的布局样式;

    SVGAAnimationController 是对 AnimationController 进一层封装与应用,调用的方法和状态回调基本是一致的;

enum AnimationStatus {
  /// 动画开始时结束
  dismissed,

  /// 动画开始
  forward,

  /// 逆向动画
  reverse,

  /// 动画完成结束
  completed,
}

this.animationController ?.addStatusListener((status) => print('---status---$status'));

    SVGAAnimationController 提供了常用的播放方法,小菜简单尝试几种常用的;

  • reset 动画重置;
  • forward 动画播放,小菜建议若动画从头开始播放先调用 reset 使动画重置,防止其他操作影响动画起始位置;
  • stop 动画停止,与 Lottie 动画不同,SVGAAnimationController 没有提供对应的暂停方法,小菜将 stop 理解为暂停和停止,若继续播放则调用 forward 即可;
  • reverse 动画反转,即反向播放动画;
  • repeat 动画重复;
  • fling 使用临界阻尼弹簧和初始速度驱动动画;小菜简单理解在正向播放时,fling 会按起始速度播放完成;
@override
void initState() {
  super.initState();
  this.animationController = SVGAAnimationController(vsync: this)
    ..addListener(() {
      if (mounted) { setState(() {}); }
    });
  this._loadAnimation();
}

@override
void dispose() {
  this.animationController?.clear();
  this.animationController?.dispose();
  this.animationController = null;
  super.dispose();
}

void _loadAnimation() async {
  final videoItem = await _loadSVGA(false, 'images/posche.svga');
  if (mounted)
    setState(() {
      this.isLoading = false;
      this.animationController?.videoItem = videoItem;
      this.animationController ?.addStatusListener((status) => print('---status---$status'));
    });
}

Widget _itemBtn(str) => Expanded(
    child: Container(
        margin: EdgeInsets.all(1.0),
        child: FlatButton(
            color: Colors.lightBlueAccent,
            child: Text(str),
            onPressed: () {
              if (str == 'start') {
                animationController?.reset();
                animationController?.forward();
              } else if (str == 'reverse') {
                animationController?.reverse();
              } else if (str == 'repeat') {
                animationController?.repeat();
              } else if (str == 'resume') {
                animationController?.forward();
              } else if (str == 'stop') {
                animationController?.stop();
              } else if (str == 'fling') {
                animationController?.fling();
              }
              setState(() {});
            })));

SVAG & Lottie

    小菜查阅了一些资料,简单了解了 SVGALottie 动画实现方式的差异;SVGA 是将 SVGA 矢量图逐帧绘制,通过设置帧率,来生成一个配置文件,使得每一帧都有一个配置,每一帧都是关键帧,通过帧率去刷每一帧的画面,这个思路跟 GIF 很像,但是通过配置使得动画过程中图片都可以得到复用;

    而 Lottie 动画是逐层绘制,将所有的动画拆成多个层级,每个层级 layer 都有一个动画配置,播放时解析多 0layer 的配置,并给每个 layer 做相应的动画;

    两种动画模式都是很成熟且应用范围很广的动画,小菜因未找到完全相同的动画元素,未能进行准确的数据分析,但查阅资料两者性能基本持平,具体选用哪种根据实际情况而定;


    SVGA 案例源码


    小菜对 SVGA 的研究还很浅显,有很多方法未研究到;如有错误,请多多指导!

来源: 阿策小和尚

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容