作者:京东物流 沈亮堂

在App开发进程中,假如想完成动画作用,能够大略分为两种办法。一种是直接用代码编写,像平移、旋转等简略的动画作用,都能够这么干,假如稍微杂乱点,就会对开发工程师的数学功底、图形图像学功底有很高的要求。

另一种办法,能够让UI同学合作,一次性出多张图片或许直接出一张GIF图,经过短时刻内快速轮播图片的办法来完成杂乱动画作用,这种办法真正完成起来仍是有挺多问题的,比如短少对动画进程的操控、图片尺寸的适配等等。那么,有没有更好的解决方案呢?

有的,Rive。

简介

Rive是专门为简化动画的完成而生的,规划师能够在其官网经过迁延拽完成各种杂乱动画作用,规划完毕后导出动画文件,工程师能够在App里直接导入此文件,合作相应的SDK即可完成。

其官网有具体的开发文档,一起也有自己的社区资源,我们能够直接从社区里下载他人规划好的动画作用进行学习。另外特别重要的是,Rive支持跨平台,一起支持Android、iOS、Flutter、JS、React、C++等等,本文以Flutter的完成为例介绍。

一个完整的比如

  1. 登陆Rive官网进行规划,并导出相应的动画文件,Rive的动画文件是以.riv结尾。

本文示例是从官网的社区里找的一个个人比较喜爱的动效。

  1. 依次运转下面的指令,引入rive sdk。

App复杂动画实现——Rive保姆级教程 | 京东云技术团队

  1. 将导出的.riv文件放到资源目录下,并修正pubspec.yaml文件。

App复杂动画实现——Rive保姆级教程 | 京东云技术团队

  1. 加载动画文件并展现的核心代码:

App复杂动画实现——Rive保姆级教程 | 京东云技术团队

App复杂动画实现——Rive保姆级教程 | 京东云技术团队

核心代码就这么多,对于代码中的标示具体说明下:

  • 标示1的当地,首要作用是获取状态机操控器,fromArtboard 办法有两个参数,第二个参数是状态机的称号,这个称号需要和UI同学洽谈好,一旦确认好称号就不答应规划同学再改了,对应于规划面板界面的左下角,如下图:

App复杂动画实现——Rive保姆级教程 | 京东云技术团队

  • 标示2的当地,本例的动画是根据“数值”的改变而改变的,findInput的入参同样需要和UI同学洽谈好,一旦规划时把这个姓名改了,代码里也别忘了进行相应的修正,也在规划面板的左下角,在状态机称号的右边,如下图:

App复杂动画实现——Rive保姆级教程 | 京东云技术团队

完整的代码如下,大家能够按步骤自己操作体验下。

class RiveDemo extends StatefulWidget {
  const RiveDemo({Key? key}) : super(key: key);
  @override
  State<RiveDemo> createState() => _RiveDemoState();
}
class _RiveDemoState extends State<RiveDemo> {
  /// 状态机操控器
  StateMachineController? controller;
  /// 操控输入数值
  SMIInput<double>? valueController;
  ///画板,合作Rive widget 运用,展现动画作用。
  Artboard? riveArtboard;
  Timer? timer;
  @override
  void initState() {
    super.initState();
    //加载
    rootBundle.load('asset/rives/rive_demo.riv').then((value) async {
      final file = RiveFile.import(value);
      final artboard = file.mainArtboard;
      //1
      controller = StateMachineController.fromArtboard(artboard, 'TreeMachine');
      if (controller != null) {
        setState(() {
          artboard.addController(controller!);
          //2
          valueController = controller!.findInput('input');
          valueController!.value = -4;
        });
      }
      riveArtboard = artboard;
    });
  }
  @override
  void dispose() {
    controller?.dispose();
    stopAnimation();
    super.dispose();
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Rive Demo'),
      ),
      backgroundColor: Colors.white,
      body: Center(
        child: riveArtboard == null ? const CircularProgressIndicator() : Rive(artboard: riveArtboard!),
      ),
      floatingActionButton: SizedBox(
        height: 50,
        child: Row(
          mainAxisAlignment: MainAxisAlignment.end,
          children: [
            TextButton(
              onPressed: () {
                startAnimation();
              },
              child: const Text('start'),
            ),
            TextButton(
              onPressed: () {
                stopAnimation();
              },
              child: const Text('stop'),
            ),
            TextButton(
              onPressed: () {
                resetAnimation();
              },
              child: const Text('reset'),
            ),
          ],
        ),
      ),
    );
  }
  /// 开端动画
  void startAnimation() {
    if (timer != null) {
      return;
    }
    timer = Timer.periodic(const Duration(milliseconds: 60), (timer) {
      valueController?.value += 0.5;
    });
  }
  /// 停止动画
  void stopAnimation() {
    timer?.cancel();
    timer = null;
  }
  /// 重置动画
  void resetAnimation() {
    stopAnimation();
    valueController?.value = 0;
  }
}

总结

像本例中的动画作用,假如用代码来编写,时刻成本会很大很大,假如靠图片的堆积,完成起来也很费事,并且由于图片的数量增多,安装包的体积也会添加许多。但是用rive,完成起来却很便利,或许唯一的成本便是规划师同学的学习成本。

Rive不仅支持本地动画文件的加载,还能够将动画文件放到服务器上,利用RiveAnimation.network办法进行加载。更多的运用示例能够参阅:
github.com/rive-app/ri…

本文正在参与「金石方案」