著者: JD Logistics Shen Mingliang
アプリ開発の過程でアニメーション効果を実現したい場合、大きく分けて2つの方法があります。1つはコードに直接書く方法で、移動や回転などの簡単なアニメーション効果はこの方法で実現できますが、もう少し複雑な場合は、開発エンジニアの数学的およびグラフィックスのスキルに対する要求が高くなります。
もう 1 つの方法は、UI の学生が協力して一度に複数の画像を作成したり、GIF 画像を直接作成したり、画像を短時間ですばやく回転させることで複雑なアニメーション効果を実現したりする方法であり、それらを制御できないなど、多くの問題があります。アニメーション プロセス、画像サイズの適応など。それで、より良い解決策はありますか?
はい、リーヴ。
序章
Rive は、アニメーションの実現を簡素化するために特別に設計されています. デザイナーは、さまざまな複雑なアニメーション効果を公式 Web サイトにドラッグ アンド ドロップできます. デザインが完了したら、アニメーション ファイルをエクスポートします. エンジニアは、このファイルをアプリに直接インポートして、対応するSDKを実現できます。
その公式ウェブサイトには詳細な開発ドキュメントがあり、独自のコミュニティ リソースもあり、コミュニティから他の人が設計したアニメーション効果を直接ダウンロードして学習することができます。さらに、Rive がクロスプラットフォームをサポートし、Android、iOS、Flutter、JS、React、C++ などをサポートしていることが特に重要です。この記事では、Flutter の実装を例として紹介します。
完全な例
- Rive の公式 Web サイトにログインして、対応するアニメーション ファイルを設計およびエクスポートします。Rive のアニメーション ファイルは .riv で終わります。
この記事の例は、公式 Web サイトのコミュニティで見つかったお気に入りのダイナミック エフェクトです。
- 次のコマンドを順番に実行して、rive sdk をインポートします。
- エクスポートした .riv ファイルをリソース ディレクトリに置き、pubspec.yaml ファイルを変更します。
- アニメーション ファイルを読み込んで表示するためのコア コード:
非常に多くのコア コードがあります。コード内の注釈を詳しく説明しましょう。
- 1 の場所は主にステート マシン コントローラを取得するために使用されます. fromArtboard メソッドには 2 つのパラメータがあります. 2 番目のパラメータはステート マシンの名前です. この名前は UI 学生と交渉する必要があります. 名前が決定されると,デザインの学生は、以下に示すように、デザイン パネル インターフェイスの左下隅に対応する変更を許可されていません。
- 标注2的地方,本例的动画是根据“数值”的变化而变化的,findInput的入参同样需要和UI同学协商好,一旦设计时把这个名字改了,代码里也别忘了进行相应的修改,也在设计面板的左下角,在状态机名称的右边,如下图:
完整的代码如下,大家可以按步骤自己操作体验下。
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…
本文正在参加「金石计划」