
2019年12月12日,Flutter 在 Flutter Interact '19 上發(fā)布了如何使用 Rive 和 Flutter 制作動態(tài)可交互的動畫經(jīng)驗分享,我看了之后,覺得非常有趣,因此,寫了3個小 demo,把它寫成文章記錄分享給大家。
名詞理解
首先,我們來理解幾個名詞,不然后續(xù)文章,可能看著有些暈,如下:
- Flare:是 Flutter 的動畫插件名稱,完整名稱是
flare_flutter我們要在pubspec.yaml文件里引入 - Rive:是制作 Flare 動畫的網(wǎng)站,它既是一個網(wǎng)站也是制作工具,在此網(wǎng)站里有很多用戶分享 Flare 動畫供我們下載使用、Flare API使用文檔、制作 Flare 動畫的視頻教程(大家也可以通過學(xué)習(xí)制作自己喜歡的動畫)等
交互動畫預(yù)覽
登錄交互動畫
登錄交互動畫,包含如下6種動畫:
- idle:無任何操作時的狀態(tài)(熊的身體會上下浮動和眨眼睛)
- test:當(dāng)我們在 email 輸入框中輸入時的狀態(tài)(熊會看向輸入框,且隨著你輸入的長度旋轉(zhuǎn)頭部)
- hands_up:當(dāng)我們在 password 輸入框中輸入時的狀態(tài) (熊會用手蒙上眼睛)
- hands_down:當(dāng)我們在 password 輸入框輸入完成時的狀態(tài) (熊會放下雙手)
- fail:當(dāng)我們登錄失敗時的狀態(tài)(熊會做出難過的表情)
- success:當(dāng)我們登錄成功時的狀態(tài)(熊會做出高興的表情)
以上6種狀態(tài),可以在 Rive 網(wǎng)站查看具體動畫,點擊進入查看
下面,我們來看看案例里實現(xiàn)動畫效果
idle:無任何操作時的狀態(tài),如圖:

test:當(dāng)我們在 email 輸入框中輸入時的狀態(tài),如圖:

hands_up:當(dāng)我們在 password 輸入框中輸入時的狀態(tài),hands_down:當(dāng)我們在 password 輸入框輸入完成時的狀態(tài),如圖:

fail:當(dāng)我們登錄失敗時的狀態(tài),如圖:

success:當(dāng)我們登錄成功時的狀態(tài),如圖:

Button交互動畫
button 交互動畫,如圖:

Menu交互動畫
menu 交互動畫,如圖:

以上所有動畫,也可以 點擊觀看視頻
代碼實現(xiàn)
如何用代碼實現(xiàn),分為以下2個步驟:
- 引入插件和資源:引入相關(guān)插件
flare_flutter、smart_flare - 編寫代碼:編寫相關(guān)代碼
引入插件和資源
引入插件和資源,如下:
dependencies:
...
flare_flutter: ^2.0.4 # flare 插件
smart_flare: any # 對 flare API進行封裝的插件,使用少量的代碼即可實現(xiàn)交互動畫
...
assets:
...
- assets/Teddy.flr
- assets/button-animation.flr
- assets/slideout-menu.flr
...
編寫代碼
由于,登錄交互動畫稍復(fù)雜一些,在此就不展示實現(xiàn)的代碼,如感興趣,可移步GitHub查看源碼
Button交互動畫代碼實現(xiàn)
button 交互動畫代碼實現(xiàn)如下:
import 'package:flutter/material.dart';
import 'package:smart_flare/actors/smart_flare_actor.dart';
import 'package:smart_flare/models.dart';
class FlareButtonDemo extends StatefulWidget {
@override
_FlareButtonDemoState createState() => _FlareButtonDemoState();
}
class _FlareButtonDemoState extends State<FlareButtonDemo> {
@override
Widget build(BuildContext context) {
var animationWidth = 295.0;
var animationHeight = 251.0;
var animationWidthThirds = animationWidth / 3;
var halfAnimationHeight = animationHeight / 2;
var activeAreas = [
ActiveArea(
area: Rect.fromLTWH(0, 0, animationWidthThirds, halfAnimationHeight),
debugArea: false,
guardComingFrom: ['deactivate'],
animationName: 'camera_tapped',
),
ActiveArea(
area: Rect.fromLTWH(animationWidthThirds, 0, animationWidthThirds, halfAnimationHeight),
debugArea: false,
guardComingFrom: ['deactivate'],
animationName: 'pulse_tapped'),
ActiveArea(
area: Rect.fromLTWH(animationWidthThirds * 2, 0, animationWidthThirds, halfAnimationHeight),
debugArea: false,
guardComingFrom: ['deactivate'],
animationName: 'image_tapped'),
ActiveArea(
area: Rect.fromLTWH(0, animationHeight / 2, animationWidth, animationHeight / 2),
debugArea: false,
animationsToCycle: ['activate', 'deactivate'],
onAreaTapped: () {
print('Button tapped!');
})
];
return Scaffold(
appBar: AppBar(
title: Text('Flare Button Demo'),
),
body: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Color(0x3fffeb3b),
Colors.orange,
]),
),
child: Align(
alignment: Alignment.bottomCenter,
child: SmartFlareActor(
width: animationWidth,
height: animationHeight,
filename: 'assets/button-animation.flr',
startingAnimation: 'deactivate',
activeAreas: activeAreas,
),
),
),
);
}
}
Menu交互動畫代碼實現(xiàn)
menu 交互動畫代碼實現(xiàn),如下:
import 'package:flutter/material.dart';
import 'package:smart_flare/smart_flare.dart';
class FlareSidebarMenuDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
print(MediaQuery.of(context).size.height);
return Scaffold(
body: Container(
child: Align(
alignment: Alignment.centerRight,
child: PanFlareActor(
width: MediaQuery.of(context).size.width / 2.366,
height: MediaQuery.of(context).size.height,
filename: 'assets/slideout-menu.flr',
openAnimation: 'open',
closeAnimation: 'close',
direction: ActorAdvancingDirection.RightToLeft,
threshold: 20.0,
reverseOnRelease: true,
completeOnThresholdReached: true,
activeAreas: [
RelativePanArea(
area: Rect.fromLTWH(0, .7, 1.0, .3), debugArea: false),
],
),
),
),
);
}
}
以上3個交互動畫案例的源碼,放在了我2年前寫的一個 Flutter案例 的項目里了,此項目現(xiàn)已維護起來,以后會長期更新,感興趣的小伙伴可以收藏,沒事時來看看可能會有新的發(fā)現(xiàn) ??
此篇文章到此結(jié)束,下篇文章計劃給大家分享,F(xiàn)lutter 里的路由,會總結(jié)歸納所有的路由使用方法,最后來封裝一個優(yōu)秀的路由管理類。
之后附上博客和項目地址,如下:
博客地址:https://h.lishaoy.net/flutter-flare
項目地址:https://github.com/persilee/flutter_pro