# Flutter 工程化框架选择——搞定 Flutter 动画 > 本文为稀土掘金技术社区首发签约文章,14天内禁止转载,14天后未获授权禁止转载,侵权必究! 首先,这次会写一个新的系列《Flutter 工程化框架选择》,但是系列其实并非前端的工程治理方面的内容,**这个系列只是单纯告诉你,创建一个 Flutter 工程,或者说搭建一个 Flutter 工程脚手架,应该如何选择快速适合自己的插件模块,或者说这是一个指引系列,相信会适合新手同学**。 > **为什么会想要写一个这样的系列?因为这类的问题太多了**,简单检索一个群的聊天记录,单单 `有没有` 这个关键字就可以搜索翻好几页,所以这个系列的目的,是帮大家整理 Flutter 工程里可能会需要的各种第三方模块,并对比一些技术细节,**也是方便以后回答问题我可以直接甩链接**。 ![](http://img.cdn.guoshuyu.cn/20220920_Z1/image1.png) 首先作为系列第一篇文章,本篇我们先聊动画。 为什么第一篇聊它,因为近期刚好做了一些关于 Flutter 动画的调研,不久前也刚好发布过一些关于它的内容,所以素材比较多,而本篇将针对你可能会遇到的动画场景,**给你推荐各式各样的动画框架来加速开发**。 # 前言 在之前的 [Flutter 小技巧](https://juejin.cn/post/7111071430292275213) 系列里我们聊过,如果没有使用封装, Flutter 里创建动画一般需要: - `AnimationController` : 用于控制动画启动、暂停 - `TickerProvider` : 用于创建 `AnimationController` 所需的 `vsync` 参数,一般最常使用 `SingleTickerProviderStateMixin` - `Animation` : 用于处理动画的 value ,例如常见的 `CurvedAnimation` - 接收动画的对象:例如 `FadeTransition` 这种写法如下代码所示,我们一般可以称为显式动画(不要纠结名词叫法),大致特征就是:以 **`*Transition`** 命名,比如 `FadeTransition` 、`SizeTransition` 和 `RotationTransition` 等,**需要我们自己定义和操作 `AnimationController`** 。 ```dart class _AnimatedOpacityState extends State with TickerProviderStateMixin { late final AnimationController _controller = AnimationController( duration: const Duration(seconds: 2), vsync: this, )..repeat(reverse: true); late final Animation _animation = CurvedAnimation( parent: _controller, curve: Curves.easeIn, ); @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Container( color: Colors.white, child: FadeTransition( opacity: _animation, child: const Padding(padding: EdgeInsets.all(8), child: FlutterLogo()), ), ); } } ``` 但是,如果都采用这种方式去使用动画,那么项目里就会存在很多的重复代码,所以 Flutter 官方默认提供了一些动画封装,也可以叫做隐式动画(不要纠结名词叫法): > **也就是开箱即用**,常见是 **`Animated*`** 开头的 Widget,例如 `AnimatedPositioned` 、`AnimatedContainer` 、 `AnimatedPadding` 、`AnimatedOpacity` 等控件,它们最大的特点就是内部已经完全封装好逻辑,你只需要配置对应参数就可以触发动画。 如下代码所示,你只需要改变 `_width` 和 `_height` 就可以触发动画效果,动画中间过程的数据会通过 `Curves` 变化的 “插值” 来得到。 ```dart body: Center( child: AnimatedContainer( width: _width, height: _height, decoration: BoxDecoration( color: _color, borderRadius: _borderRadius, ), duration: Duration(seconds: 1), curve: Curves.fastOutSlowIn, ), ), ``` 虽然隐式动画挺方便,但真正的项目里可能很多情况还是不满我们的需求,往往业务逻辑会需要更灵活或者更细致的封装,那么这就要聊到本篇后面的内容。 # 基础动画 说到基础动画的部分,主要就是在隐式动画的基础上进一步的封装,可以通过简单配置快速实现一些更精致的动画效果。 ## animations [animations](https://github.com/flutter/packages/tree/main/packages/animations) 是官方封装的动画库,主要卖点在于 Material 风格的动画过渡,所以**这个库的核心重点是路由过渡动画或者页面切换动画**,例如下图就是 Demo 里利用库里自带的 `OpenContainer` 实现页面跳转的 Material 过渡 效果。 ![](http://img.cdn.guoshuyu.cn/20220920_Z1/image2.gif) 另外也可以使用 `PageTransitionSwitcher` 实现一些非路由的页面切换动画,可以理解为是一个变异版本的 `AnimatedSwitcher` ,或者是 `Stack` 版动画 `PageView` ,不过支持自定义进入和退出动画,还可以支持自定义布局,一般默认使用默认 `defaultLayoutBuilder` 的话,就是使用 `Stack` 作为布局。 ![](http://img.cdn.guoshuyu.cn/20220920_Z1/image3.gif) 官方 Demo 里也会使用 `PageTransitionSwitcher` 来做步进页面跳转的效果,**所以 [animations](https://github.com/flutter/packages/tree/main/packages/animations) 的核心动画能力主要是在于页面过渡方面**。 ![](http://img.cdn.guoshuyu.cn/20220920_Z1/image4.gif) > 总的来说,这个库是官方维护,值得信赖。 ## simple_animations [simple_animations](https://github.com/felixblaschke/simple_animations) 如同它的名字所示,它主要是简化了自定义动画的过程,正如前面所示,在 Flutter 里使用动画,我们一般需要定义 `AnimationController` 、`Animatable` 和 `Animation` 等对象来配置动画效果。 而 simple_animations 提供了 `AnimationMixin` 对象,如下代码所示,你只需要通过 `with` 关键字就可以简化接入动画的代码。 | ![](http://img.cdn.guoshuyu.cn/20220920_Z1/image5.gif) | ![](http://img.cdn.guoshuyu.cn/20220920_Z1/image6.png) | ![](http://img.cdn.guoshuyu.cn/20220920_Z1/image7.gif) | | ------------------------------------------- | ----------------------------------------------------------- | ----------------------------------------------------- | 同时 simple_animations 也提供了各种 Builder 来简化,例如使用 `MirrorAnimationBuilder` 就可以实现一个循环反复的动画效果。 ![](http://img.cdn.guoshuyu.cn/20220920_Z1/image8.png) **所以 simple_animations 针对显式动画进行了优化封装,在更方便的情况下做到能更灵活控制动画效果**,如下图所示,在 [gsy_fluter_demo](https://github.com/CarGuo/gsy_flutter_demo/tree/master/lib/widget/particle) 里就利用了 simple_animations 来实现一些动画效果: - `MirrorAnimation` 和 `MovieTween ` 实现渐变的背景 - `LoopAnimation` 和 `MovieTween` 实现了粒子动画 | ![](http://img.cdn.guoshuyu.cn/20220920_Z1/image9.gif) | ![](http://img.cdn.guoshuyu.cn/20220920_Z1/image10.gif) | | ---------------------------------------- | ------------------------------------------ | > 不过这个库有个小问题,就是它最近几次大版本,每个版本总是会有一些 break change ,但是可能就是改改名字,换换参数位置,如果你一段时间没关注,再升级可能会有些成本。 ## animate_do **[animate_do](https://github.com/Klerith/animate_do_package) 是一个轻量级动画包,它比 simple_animations “更懒”,代码也相对简单很多,内部提供了丰富的动画封装 Widget 可直接使用**。 > 你可以理解为更丰富的隐式动画。 animate_do 就是通过 `AnimatedBuilder ` 配合 `Transform` 、`Opacity` 进行了封装,然后开发者可以通过 `FlipInX` 、`FadeInDown` 、`ElasticIn` 等对象直接实现动画效果。 ![](http://img.cdn.guoshuyu.cn/20220920_Z1/image11.png) 既然 animate_do 十分简单,那为什么会推荐它呢?因为它真的很实用。 **首先简单代表着好维护,作者不玩了我们自己也能接**,其次 animate_do 提供了相当丰富的封装,这对于懒人来说它真的很实用,特别是对于一些 “相对复杂” 的动画效果上(如下图3)可以节省很多时间,特别是在 `Tween` 和 `CurvedAnimation`的封装上。 | ![](http://img.cdn.guoshuyu.cn/20220920_Z1/image12.gif) | ![](http://img.cdn.guoshuyu.cn/20220920_Z1/image13.gif) | ![](http://img.cdn.guoshuyu.cn/20220920_Z1/image14.gif) | | --------------------------------------- | ----------------------------------------- | --------------------------------------- | > 目前有一段时候没更新,但是问题不大~ 同类型的库还有 [spring](https://github.com/KaushickSArgekar/spring) ,可以作为替代项目,也实现了类似的封装。 # UI 动画 介绍完基础动画效果,接下来推荐一些常用的动画框架,因为经常有人问到`有没有xxx` 的实现可以直接拿来使用,秉承着有做好的就不自己动手原则,下面这些 UI 动画框架,也许在你开发过程中就会需要用到。 > UI 动画部分就不介绍实现了,主要就看功能符不符合你需求。 ## 数字动画 首先是数字动画,常见的有 [flutter-animated-counter](https://github.com/h65wang/flutter-animated-counter) ,本身它就提供了丰富的 API 和动画效果,类似的第三方库还有 [odometer](https://github.com/KirsApps/odometer) 和 [animated_digit ](https://github.com/mingsnx/animated_digit) 等,具体可以自己按需选择。 | ![](http://img.cdn.guoshuyu.cn/20220920_Z1/image15.gif) | ![](http://img.cdn.guoshuyu.cn/20220920_Z1/image16.gif) | ![](http://img.cdn.guoshuyu.cn/20220920_Z1/image17.gif) | | ------------------------------------------- | ------------------------------------------- | ----------------------------------------- | ## 跑马灯 既然聊到文字动画,就不得不说跑马灯,如下表格所示是 Flutter 里常用到的文字跑马灯的第三方 package ,其中 [marquee_widget](https://github.com/yousifk/marquee_widget) 提供的接口相对更佳丰富。 | [marquee_widget](https://github.com/yousifk/marquee_widget) | [text_scroll](https://github.com/yurii-khi/text_scroll) | [marquee_text](https://pub.dev/packages/marquee_text) | | ----------------------------------------------------------- | ------------------------------------------------------------ | ----------------------------------------------------- | | ![](http://img.cdn.guoshuyu.cn/20220920_Z1/image18.gif) | ![](http://img.cdn.guoshuyu.cn/20220920_Z1/image19.gif) | ![](http://img.cdn.guoshuyu.cn/20220920_Z1/image20.gif) | ## 加载动画 加载动画是最常见的 UI 动画,如果你没有设计师,如果你不知道 loading 动画用什么好,那你可以考虑下面几个 package,这三个 loading 库都是纯代码实现,提供了丰富的样式选择。 | [flutter_spinkit](https://github.com/jogboms/flutter_spinkit) | [loading_animation_widget](https://github.com/watery-desert/loading_animation_widget) | [loading_indicator](https://github.com/TinoGuo/loading_indicator) | | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | | ![](http://img.cdn.guoshuyu.cn/20220920_Z1/image21.gif) | ![](http://img.cdn.guoshuyu.cn/20220920_Z1/image22.gif) | ![](http://img.cdn.guoshuyu.cn/20220920_Z1/image23.gif) | > 纯代码实现有什么好处?当样式需要做一些简单调整时,作为开发者可以通过代码快速修改,这是我喜欢纯代码实现动画的原因。 ## 指引动画 指引动画也是常见的需求之一,基本实现都会通过 `Overlay` 来完成,不同的可能就是动画效果和定位方式的差异,具体也可以按照自己的需要选择。 | [feature_discovery](https://github.com/ayalma/feature_discovery) | [flutter_showcaseview](https://github.com/simformsolutions/flutter_showcaseview) | [flutter_intro](https://pub.dev/packages/flutter_intro) | [BubbleShowcase](https://github.com/Skyost/BubbleShowcase) | | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------- | ---------------------------------------------------------- | | ![](http://img.cdn.guoshuyu.cn/20220920_Z1/image24.gif) | ![](http://img.cdn.guoshuyu.cn/20220920_Z1/image25.gif) | ![](http://img.cdn.guoshuyu.cn/20220920_Z1/image26.gif) | ![](http://img.cdn.guoshuyu.cn/20220920_Z1/image27.gif) | ## 列表动画 列表动画也是常见的 UI 动画能力之一,基本上 Flutter 上最常见用都的第三方列表动画库就是下面表格里这三个,坑还是有的,但是“又不是不能用”。 | [flutter_staggered_animations](https://github.com/mobiten/flutter_staggered_animations) | [animation_list](https://github.com/turlvo/flutter_animation_list) | [transformable_list_view](https://github.com/TBR-Group-software/transformable_list_view) | | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | | ![](http://img.cdn.guoshuyu.cn/20220920_Z1/image28.gif) | ![](http://img.cdn.guoshuyu.cn/20220920_Z1/image29.gif) | ![](http://img.cdn.guoshuyu.cn/20220920_Z1/image30.gif) | ## 3D 立体动画 这个类目可能关注的人反而不是很多,但是恰好是我近期比较关注的动画实现,这里主要推荐两个利用矩阵变换绘制 3D 视觉效果的第三方库,它们不同在于: - zwidget 能力相对比较弱,直接使用的是 `Transform` 的能力 - zflutter 来源于前端 zdog 项目,是直接对 `Canvas` 的 `path` 进行矩阵变换 | [zflutter](https://github.com/jamesblasco/zflutter) | [zwidget](https://github.com/apalala-dev/zwidget) | | --------------------------------------------------- | ------------------------------------------------------ | | ![](http://img.cdn.guoshuyu.cn/20220806_N11/image30.gif) | ![](http://img.cdn.guoshuyu.cn/20220920_Z1/image31.gif) | 在不久前我也写过一篇文章 [《Flutter 实现 “真” 3D 动画效果》](https://juejin.cn/post/7129239231473385503),内容主要分析了 zflutter 的实现逻辑和如何使用 zflutter ,利用纯代码渲染 3D 效果的动画。 > 当然,上门两个 3D 动画,它们在使用上相对会比较复杂,如果需要更高级的动画效果,建议看下面的推荐。 # 高级动画支持 介绍完面向程序员的动画支持之后,最后我们来介绍两个面向设计师的动画支持库,同时也是更好支持复杂动画实现的库。 ## Lottie [Lottie](https://github.com/xvrh/lottie-flutter) 相信大家不会陌生,[airbnb ](https://github.com/airbnb) 最优秀的动画开源库,设计师可以通过 AE 插件导出设计好的动画效果,然后利用平台的 `Canvas` 等能力渲染出 AE 上的动画效果。 ![](http://img.cdn.guoshuyu.cn/20220920_Z1/image32.gif) **使用 Lottie 的好处在于,设计师可以更自由的去尝试更炫酷的动画**,而程序员只需要关心如何控制动画(时长,循环,方向,帧率等),同时因为动画大部分时候都是矢量数据,所以 Lottie 文件相对不大。 > 在早期的时候,由于 Lottie 本身只支持原生平台,所以 Flutter 上都是通过外界纹理或者 `PlatformView ` 等形式接入,这样的后果就是导致各种性能和兼容问题,好在现在 [lottie-flutter](https://github.com/xvrh/lottie-flutter) 已经支持 Dart `Canvas` 的原生 API 。 当然, Lottie 本身的问题也很明显,那就是你的交互设计师要会 AE ,很遗憾的是,我接触的大部分设计师都不会 AE ,而且会 AE 还不够,还需要会 [Bodymovin](https://github.com/airbnb/lottie-web) 插件相关的兼容,熟悉什么属性可以用,整体开发环境也比较重。 ## Rive 对于 **[rive](https://link.juejin.cn/?target=https%3A%2F%2Frive.app)** 可能大家会感觉比较陌生,而做过 Flutter 开发的可能对 rive 会有所耳闻,因为 rive 在此之前叫 flare ,是 2dimensions 公司的开源动画产品,在发布之初由于和 Flutter 团队有深入合作,所以在初期一直是 Flutter 官方推荐的动画框架。 | ![](http://img.cdn.guoshuyu.cn/20220731_N10/image3.gif) | ![](http://img.cdn.guoshuyu.cn/20220731_N10/image4.png) | | ------------------------------------------------------- | ------------------------------------------------------- | **[rive](https://link.juejin.cn/?target=https%3A%2F%2Frive.app)** 同样是一个面向设计师的动画框架,只不过他是在 **Web Editor** 里进行 UI 编排和动画绘制,所以他在开发环境上相对会轻量化。 | ![](http://img.cdn.guoshuyu.cn/20220731_N10/image18.gif) | ![img](http://img.cdn.guoshuyu.cn/20220731_N10/image9.gif) | ![img](http://img.cdn.guoshuyu.cn/20220731_N10/image10.gif) | | ------------------------------------------- | ---------------------------------------------------------- | ----------------------------------------------------------- | 同时 rive 同样是通过导出矢量的动画数据文件(也可以包含一些静态资源),然后利用平台的 `Canvas` 来实现动画效果,所以它的占用提及也不会很大。 另外 rive 现在也是全平台支持, **Android、 iOS、Web、Desktop、Flutter 、React、Vue、C++** 等都在支持范围之内。 > 如果想深入了解 rive ,也可以看我之前的 [《给掘金 Logo 快速添加动画效果》](https://juejin.cn/post/7126661045564735519) ,其实对于程序员来说,rive 同时很好上手。 ![](http://img.cdn.guoshuyu.cn/20220731_N10/image1.gif) > 目前 rive 的问题是,第二代 rive 和第一代 flare 存在断档不兼容,而且基本可以忽略迁移的可能,同时没有本地化免费开发 IDE 有时候也是一种麻烦。 好了,关于 Flutter 动画相关的内容推荐就到这里,如果你还有什么关于 Flutter 工程或者框架的疑问,欢迎留言评论,也许又可以多一期的素材~