30分钟学会Flutter动画开发

 

文章目录

  • 前言
  • 一、flutter动画组成要素和载体
  • 二、常用的四种动画的实现
  • 三、列表组动画Group Animation的实现
  • 四、第三方动画框架的介绍和使用
  • 结束语

 


前言

动画是UI交互的重要组成部分,精心设计的动画会让用户界面感觉更直观、流畅,能改善用户体验。flutter作为跨平台的UI框架,对动画提供了良好的支持和简单轻松的实现,本文对flutter动画的类型和动画方式以及第三方的动画框架做一点总结,希望对大家有所帮助。

Flutter的动画支持可以轻松实现各种动画类型。许多widget,特别是Material Design widgets, 都带有在其设计规范中定义的标准动画效果,但也可以自定义这些效果。

一、flutter动画组成要素和载体

flutter动画一般有4部分要素组成,分别是Animation、AnimationController、Curve、Tween。它们的关系如下图:

Animation<T>:代表一个动画,是动画的核心类,可以从通过animation.value拿到当前动画的值,以及读取到当前当前动画的状态(例如它是开始、停止还是向前或向后移动)

AnimationController:顾名思义就是动画的控制器,可以控制动画的开始、停止、向前向后还有重复执行等操作。在页面销毁的时候,记得要调用controller的dispose方法,否则会有内存泄漏的风险。

Curve:动画运动过程中的速率的曲线,比如可以定义匀速运动,先快后慢、先慢后快等。

Tween:动画的取值范围,默认是0.0~1.0,如果需要定义动画不同的类型和范围,可以通过Tween的begin和end来指定。

Tween通过animate方法可以生成指定区间的全新动画。

所以,四个要素组合起来,一般的动画定义代码为:

final AnimationController controller = AnimationController(duration: const Duration(milliseconds: 500), vsync: this);

final Animation curve = CurvedAnimation(parent: controller, curve: Curves.easeOut);

Animation<int> animation = IntTween(begin: 0, end: 255).animate(curve);

 动画定义完成之后,在UI树中需要一个动画的载体来完成动画。flutter承载动画的组件是AnimatedWidget和ImplicitlyAnimatedWidget,为了方便开发者开发动画,AnimatedWidget和ImplicitlyAnimatedWidget提供了很多子类,AnimatedWidget的子类概览如下图:

AnimatedWidget和ImplicitlyAnimatedWidget的区别就是:AnimatedWidget需要开发者自己定义一个animation传递给它,并且自己管理AnimationController,而ImplicitlyAnimatedWidget只需要给它设定一个目标值和duration,它就会开始动画,并且内部自己管理一个AnimationController,简化了操作。

 

二、常用的四种动画实现

一般场景下,常用到的动画主要有以下四种:渐隐渐现动画、位移动画、旋转动画、放大缩小动画。

在flutter中,这四种动画都有对应的封装类

渐隐渐现动画 -- FadeTransition

位移动画 -- SlideTransition

旋转动画 -- RotationTransition

放大缩小动画 -- ScaleTransition

它们的用法都是类似,首先是定义一个animation,然后将animaton作为关键参数传给对应的AnimatedWidget。

下面就透明度动画和位移动画做一个简单的示例,其他两种动画都是类似的用法

首先是创建一个透明动画对象和位移动画对象:

AnimationController _controller;
  Animation<double> _animation;
  Animation<Offset> _offsetAnimation;

  @override
  void initState() {
    super.initState();
    _controller =
        AnimationController(vsync: this, duration: Duration(seconds: 2))
          ..repeat(reverse: true);
    _animation = CurvedAnimation(parent: _controller, curve: Curves.easeIn);
    _offsetAnimation = Tween<Offset>(begin: Offset.zero, end: Offset(1.5, 0.0))
        .animate(_controller);
  }

然后是将animation对象作为参数传给对应的动画组件:

Row(
    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
    children: [
      FadeTransition(
        opacity: _animation,
        child: FlutterLogo(
          size: 150,
        ),
      ),
      SlideTransition(
        position: _offsetAnimation,
        child: FlutterLogo(
          size: 150,
        ),
      ),
    ],
  )

这样就实现了两个动画,可以说flutter实现动画还是非常简单的,简化了开发者的工作。

如果这四种动画想混合使用,应该怎么做呢?比如在位移的过程中,还要有透明度的变化,可能还有大小的变化。

答案是将这几个AnimatedWidget嵌套使用:

@override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(''),
      ),
      body: Container(
        alignment: Alignment.topCenter,
        child: FadeTransition(
          opacity: _animation,
          child: SlideTransition(
            position: _offsetAnimation,
            child: ScaleTransition(
              scale: _animation,
              child: FlutterLogo(
                size: 150,
              ),
            ),
          ),
        ),
      ),
    );
  }

效果如下:

需要注意的是,这几个嵌套使用的animation,必须使用同一个AnimationController。

 

三、列表组动画Group Animation的实现

如果想让一个ListView里面的组件都执行一个动画,这就是group animation的概念,就像这样:

要实现这样的组动画,flutter中提供了一个AnimatedList的组件,大体的使用结构如下

@override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(''),
      ),
      body: AnimatedList(
        key: _listKey,
        initialItemCount: itemList.length,
        itemBuilder: (context, index, animation) {
          return SlideTransition(
            position: animation
                .drive(CurveTween(curve: Curves.easeIn))
                .drive(Tween<Offset>(begin: Offset(-1, 0), end: Offset(0, 0))),
            child: CardItem(item: index),
          );
        },
      ),
    );
  }

四、第三方动画框架介绍和使用

一些优秀的第三方动画框架也对flutter进行了支持,比如lottie、flare和svga

1) Flare

Flare是一家可以快速制作矢量动画的网站,提供专门的Flutter组件来承载网站导出的动画文件,使用Flare创建的动画不仅可以有效减少安装包的体积,还能创建更加复杂绚丽的动画体验。Flare动画最早出现在2019年12月举行的Flutter技术大会上,一经发布立马受到开发者的喜爱和追捧。

作为一个专业制作矢量动画的网站,Flare提供了非常丰富的免费矢量动画。由于Flare并没有提供桌面版的开发工具,所以创建Flare动画之前需要登录Flare官网来制作Flare动画文件,如果还没有Flare账号可以先注册一个。

Flare通常以工程形式来创建和管理动画项目,目前Flare支持创建动画项目有两类,分别是Flare和Nima,它们的区别如下。

Flare:为App和Web构建实时、快速的动画,同时也支持构建游戏应用动画。
Nima:为游戏引擎和应用构建2D动画。
由于Nima主要用于构建2D游戏动画,所以如果是普通的应用开发只需要新建一个Flare项目即可

目前Flare也对flutter提供了支持,具体的使用方法可以参考pub.dev:https://pub.dev/packages/flare_flutter

import 'package:flare_flutter/flare_actor.dart';
class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return new FlareActor("assets/Filip.flr", alignment:Alignment.center, fit:BoxFit.contain, animation:"idle");
  }
}

2)Lottie

Lottie是Airbnb开源的一个动画渲染库,支持多平台,包括iOS、Android、React Native以及Flutter.

  • 动效设计师使用After Effects制作动画,然后使用Bodymovin导出JSON文件,可以将JSON文件放到Bodymovin网站上运行看效果,也可以放在lottiefiles网站上运行看效果,而且lottiefiles有很多免费动画JSON资源可以下载看
  • 各个端使用对应的Lottie SDK加载JSON文件,实现动画效

目前Lottie也对flutter提供了支持,具体的使用方法可以参考pub.dev:https://pub.dev/packages/lottie

import 'package:flutter/material.dart';
import 'package:lottie/lottie.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: ListView(
          children: [
            // Load a Lottie file from your assets
            Lottie.asset('assets/LottieLogo1.json'),

            // Load a Lottie file from a remote url
            Lottie.network(
                'https://raw.githubusercontent.com/xvrh/lottie-flutter/master/example/assets/Mobilo/A.json'),

            // Load an animation and its images from a zip file
            Lottie.asset('assets/lottiefiles/angel.zip'),
          ],
        ),
      ),
    );
  }
}

结束语

以上就是对flutter动画的做的一点总结和介绍,当然还有很多其他类型的动画没有介绍,比如页面转场动画和共享元素动画等。丰富的动画场景带来丰富的体验,后面会继续探索。