Flutter 工程化框架选择——搞定 Flutter 动画

本文为稀土掘金技术社区首发签约文章,14天内禁止转载,14天后未获授权禁止转载,侵权必究!

首先,这次会写一个新的系列《Flutter 工程化框架选择》,但是系列其实并非前端的工程治理方面的内容,这个系列只是单纯告诉你,创建一个 Flutter 工程,或者说搭建一个 Flutter 工程脚手架,应该如何选择快速适合自己的插件模块,或者说这是一个指引系列,相信会适合新手同学

为什么会想要写一个这样的系列?因为这类的问题太多了,简单检索一个群的聊天记录,单单 有没有 这个关键字就可以搜索翻好几页,所以这个系列的目的,是帮大家整理 Flutter 工程里可能会需要的各种第三方模块,并对比一些技术细节,也是方便以后回答问题我可以直接甩链接

首先作为系列第一篇文章,本篇我们先聊动画。

为什么第一篇聊它,因为近期刚好做了一些关于 Flutter 动画的调研,不久前也刚好发布过一些关于它的内容,所以素材比较多,而本篇将针对你可能会遇到的动画场景,给你推荐各式各样的动画框架来加速开发

前言

在之前的 Flutter 小技巧 系列里我们聊过,如果没有使用封装, Flutter 里创建动画一般需要:

  • AnimationController : 用于控制动画启动、暂停
  • TickerProvider : 用于创建 AnimationController 所需的 vsync 参数,一般最常使用 SingleTickerProviderStateMixin
  • Animation : 用于处理动画的 value ,例如常见的 CurvedAnimation
  • 接收动画的对象:例如 FadeTransition

这种写法如下代码所示,我们一般可以称为显式动画(不要纠结名词叫法),大致特征就是:以 *Transition 命名,比如 FadeTransitionSizeTransitionRotationTransition 等,需要我们自己定义和操作 AnimationController

class _AnimatedOpacityState extends State<AnimatedOpacity>
    with TickerProviderStateMixin {
  late final AnimationController _controller = AnimationController(
    duration: const Duration(seconds: 2),
    vsync: this,
  )..repeat(reverse: true);
  late final Animation<double> _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,例如 AnimatedPositionedAnimatedContainerAnimatedPaddingAnimatedOpacity 等控件,它们最大的特点就是内部已经完全封装好逻辑,你只需要配置对应参数就可以触发动画。

如下代码所示,你只需要改变 _width_height 就可以触发动画效果,动画中间过程的数据会通过 Curves 变化的 “插值” 来得到。

body: Center(
  child: AnimatedContainer(
    width: _width,
    height: _height,
    decoration: BoxDecoration(
      color: _color,
      borderRadius: _borderRadius,
    ),
    duration: Duration(seconds: 1),
    curve: Curves.fastOutSlowIn,
  ),
),

虽然隐式动画挺方便,但真正的项目里可能很多情况还是不满我们的需求,往往业务逻辑会需要更灵活或者更细致的封装,那么这就要聊到本篇后面的内容。

基础动画

说到基础动画的部分,主要就是在隐式动画的基础上进一步的封装,可以通过简单配置快速实现一些更精致的动画效果。

animations

animations 是官方封装的动画库,主要卖点在于 Material 风格的动画过渡,所以这个库的核心重点是路由过渡动画或者页面切换动画,例如下图就是 Demo 里利用库里自带的 OpenContainer 实现页面跳转的 Material 过渡 效果。

另外也可以使用 PageTransitionSwitcher 实现一些非路由的页面切换动画,可以理解为是一个变异版本的 AnimatedSwitcher ,或者是 Stack 版动画 PageView ,不过支持自定义进入和退出动画,还可以支持自定义布局,一般默认使用默认 defaultLayoutBuilder 的话,就是使用 Stack 作为布局。

官方 Demo 里也会使用 PageTransitionSwitcher 来做步进页面跳转的效果,所以 animations 的核心动画能力主要是在于页面过渡方面

总的来说,这个库是官方维护,值得信赖。

simple_animations

simple_animations 如同它的名字所示,它主要是简化了自定义动画的过程,正如前面所示,在 Flutter 里使用动画,我们一般需要定义 AnimationControllerAnimatableAnimation 等对象来配置动画效果。

而 simple_animations 提供了 AnimationMixin 对象,如下代码所示,你只需要通过 with 关键字就可以简化接入动画的代码。

同时 simple_animations 也提供了各种 Builder 来简化,例如使用 MirrorAnimationBuilder 就可以实现一个循环反复的动画效果。

所以 simple_animations 针对显式动画进行了优化封装,在更方便的情况下做到能更灵活控制动画效果,如下图所示,在 gsy_fluter_demo 里就利用了 simple_animations 来实现一些动画效果:

  • MirrorAnimationMovieTween 实现渐变的背景
  • LoopAnimationMovieTween 实现了粒子动画

不过这个库有个小问题,就是它最近几次大版本,每个版本总是会有一些 break change ,但是可能就是改改名字,换换参数位置,如果你一段时间没关注,再升级可能会有些成本。

animate_do

animate_do 是一个轻量级动画包,它比 simple_animations “更懒”,代码也相对简单很多,内部提供了丰富的动画封装 Widget 可直接使用

你可以理解为更丰富的隐式动画。

animate_do 就是通过 AnimatedBuilder 配合 TransformOpacity 进行了封装,然后开发者可以通过 FlipInXFadeInDownElasticIn 等对象直接实现动画效果。

既然 animate_do 十分简单,那为什么会推荐它呢?因为它真的很实用。

首先简单代表着好维护,作者不玩了我们自己也能接,其次 animate_do 提供了相当丰富的封装,这对于懒人来说它真的很实用,特别是对于一些 “相对复杂” 的动画效果上(如下图3)可以节省很多时间,特别是在 TweenCurvedAnimation的封装上。

目前有一段时候没更新,但是问题不大~ 同类型的库还有 spring ,可以作为替代项目,也实现了类似的封装。

UI 动画

介绍完基础动画效果,接下来推荐一些常用的动画框架,因为经常有人问到有没有xxx 的实现可以直接拿来使用,秉承着有做好的就不自己动手原则,下面这些 UI 动画框架,也许在你开发过程中就会需要用到。

UI 动画部分就不介绍实现了,主要就看功能符不符合你需求。

数字动画

首先是数字动画,常见的有 flutter-animated-counter ,本身它就提供了丰富的 API 和动画效果,类似的第三方库还有 odometeranimated_digit 等,具体可以自己按需选择。

跑马灯

既然聊到文字动画,就不得不说跑马灯,如下表格所示是 Flutter 里常用到的文字跑马灯的第三方 package ,其中 marquee_widget 提供的接口相对更佳丰富。

marquee_widget text_scroll marquee_text

加载动画

加载动画是最常见的 UI 动画,如果你没有设计师,如果你不知道 loading 动画用什么好,那你可以考虑下面几个 package,这三个 loading 库都是纯代码实现,提供了丰富的样式选择。

flutter_spinkit loading_animation_widget loading_indicator

纯代码实现有什么好处?当样式需要做一些简单调整时,作为开发者可以通过代码快速修改,这是我喜欢纯代码实现动画的原因。

指引动画

指引动画也是常见的需求之一,基本实现都会通过 Overlay 来完成,不同的可能就是动画效果和定位方式的差异,具体也可以按照自己的需要选择。

feature_discovery flutter_showcaseview flutter_intro BubbleShowcase

列表动画

列表动画也是常见的 UI 动画能力之一,基本上 Flutter 上最常见用都的第三方列表动画库就是下面表格里这三个,坑还是有的,但是“又不是不能用”。

flutter_staggered_animations animation_list transformable_list_view

3D 立体动画

这个类目可能关注的人反而不是很多,但是恰好是我近期比较关注的动画实现,这里主要推荐两个利用矩阵变换绘制 3D 视觉效果的第三方库,它们不同在于:

  • zwidget 能力相对比较弱,直接使用的是 Transform 的能力
  • zflutter 来源于前端 zdog 项目,是直接对 Canvaspath 进行矩阵变换
zflutter zwidget

在不久前我也写过一篇文章 《Flutter 实现 “真” 3D 动画效果》,内容主要分析了 zflutter 的实现逻辑和如何使用 zflutter ,利用纯代码渲染 3D 效果的动画。

当然,上门两个 3D 动画,它们在使用上相对会比较复杂,如果需要更高级的动画效果,建议看下面的推荐。

高级动画支持

介绍完面向程序员的动画支持之后,最后我们来介绍两个面向设计师的动画支持库,同时也是更好支持复杂动画实现的库。

Lottie

Lottie 相信大家不会陌生,airbnb 最优秀的动画开源库,设计师可以通过 AE 插件导出设计好的动画效果,然后利用平台的 Canvas 等能力渲染出 AE 上的动画效果。

使用 Lottie 的好处在于,设计师可以更自由的去尝试更炫酷的动画,而程序员只需要关心如何控制动画(时长,循环,方向,帧率等),同时因为动画大部分时候都是矢量数据,所以 Lottie 文件相对不大。

在早期的时候,由于 Lottie 本身只支持原生平台,所以 Flutter 上都是通过外界纹理或者 PlatformView 等形式接入,这样的后果就是导致各种性能和兼容问题,好在现在 lottie-flutter 已经支持 Dart Canvas 的原生 API 。

当然, Lottie 本身的问题也很明显,那就是你的交互设计师要会 AE ,很遗憾的是,我接触的大部分设计师都不会 AE ,而且会 AE 还不够,还需要会 Bodymovin 插件相关的兼容,熟悉什么属性可以用,整体开发环境也比较重。

Rive

对于 rive 可能大家会感觉比较陌生,而做过 Flutter 开发的可能对 rive 会有所耳闻,因为 rive 在此之前叫 flare ,是 2dimensions 公司的开源动画产品,在发布之初由于和 Flutter 团队有深入合作,所以在初期一直是 Flutter 官方推荐的动画框架。

rive 同样是一个面向设计师的动画框架,只不过他是在 Web Editor 里进行 UI 编排和动画绘制,所以他在开发环境上相对会轻量化。

img img

同时 rive 同样是通过导出矢量的动画数据文件(也可以包含一些静态资源),然后利用平台的 Canvas 来实现动画效果,所以它的占用提及也不会很大。

另外 rive 现在也是全平台支持, Android、 iOS、Web、Desktop、Flutter 、React、Vue、C++ 等都在支持范围之内。

如果想深入了解 rive ,也可以看我之前的 《给掘金 Logo 快速添加动画效果》 ,其实对于程序员来说,rive 同时很好上手。

目前 rive 的问题是,第二代 rive 和第一代 flare 存在断档不兼容,而且基本可以忽略迁移的可能,同时没有本地化免费开发 IDE 有时候也是一种麻烦。

好了,关于 Flutter 动画相关的内容推荐就到这里,如果你还有什么关于 Flutter 工程或者框架的疑问,欢迎留言评论,也许又可以多一期的素材~

results matching ""

    No results matching ""