教你製作強大的 Rive 動畫,完成一隻 Flutter Dash,在 APP 跟它互動!
簡單好上手的 Rive Animation
已經想很久要製作動畫,之前想說要嘗試 Lottie 還是 Rive,動畫能製作的效果都很棒,不過 Flutter 持續有在跟 Rive 合作,社群活躍,團隊本身也有 Flutter 開發者會分享一些相關應用,讓我對它產生興趣,而且很快就能上手了,趕緊跟著我來了解吧!
- 動畫開發服務與平台,前身為 Flare
- Flutter 持續有在推廣 Rive 也經常合作,最新的作品為 Holobooth
- 跨平台支援,在任何地方都能運行的交互式動畫格式,包含手機、網頁、桌面應用,當然 APP 相關有 Android、iOS、Flutter、React Native
- 使用網頁編輯器和 MacOS 版本製作動畫
- 免費帳戶允許創建 3 個專案,每個都可創建無限的模板,對個人來說很夠用了
Rive 與 Lottie 比較
- Rive 不需要安裝額外的工具、軟體,例如:AE,可以直接在網頁上製作動畫。而現在也有了 MacOS 版本,體驗一樣好
- Rive 擁有更多與動畫互動的功能,例如:Bone、Weight、Blend…。Lottie 為矢量 GIF,能操作的互動性有限
- Rive 從製作到產出都是在相同平台,確保品質與效果在多平台都是一致的。Lottie 經由多個工具的輔助,他們都不是互相設計,所以沒辦法保證最後的顯示相同
- Rive 文件更小、更快,不太消耗裝置的記憶體
- Rive 支援團隊協作,一起設計
官方範例
圖像製作
一進來編輯器會有提供預設的 Artboard
,也就是畫板,像是程式開發的 Canvas,我們需要在上面製作、繪畫。前面有提到每個專案裡面都能新增無數個 Artboard,需要用的時候在個別導出檔案。
左邊為元素欄,我們畫的圖形、線條都會在上面展示,也可以將相關意義、區域的東西透過群組包裹,方便管理。
右邊則為自定義面板,包含基本的位置、大小、顏色,進階的有多層次顏色、裁剪、約束。
基本的矩形、圓形、多邊形和星星都可以畫,當要畫一些特別的圖象時就會用到畫筆,輕鬆能掌握弧形與對應角度,算是我最常用的一個繪畫工具
畫筆就是在特定位置點擊後產生貝茲曲線的節點,並可以進行拉伸與變換方向來改變線條,本身支援四種模式
Straight
→ 直邊線條,預設使用方式,只需確定每個頂點就會自動連結Mirrored
→ 彎曲線條,在放置頂點的時候拖拉它,根據你的方向與長短產生彎曲效果,兩邊的長度拖拉時會等長Detached
→ 曲線,兩邊獨立的曲線節點,可以個別有自己的角度和拉伸Asymmetric
→ 曲線,兩邊的角度一樣,但是拉伸曲度不同
在繪製時要注意一點,圖形的線條方向是有差異的,當兩個圖形重疊的時候,如果都是順時鐘完成那重疊部分會保留。反之如果方向不同,則重疊部分不會被填充
如果今天已經有製作了兩個圖形,他們剛好都是順時鐘完成,但是因為某些效果,又不想要重疊的地方被填充,這時候可以設置顏色裡面的規則,改為 Even-Odd,這樣就不需要考慮路徑的方向
透過線條的方式我完成了第一隻自己畫的 Dash,很有趣的過程,只是要畫出3D立體感還是有點難度,需要有一些美術技巧
動畫製作
點擊右上角的 Animate
,下方會有預設的 Timeline 時間軸,可以針對每個元素、線條、圖形去設置動畫
第一個範例,我要為 Dash 的右手設置揮手效果,直覺想到的是要調整翅膀的選轉角度,所以我在一開始新增旋轉角度為0的時間戳,接著在接近 0.1 秒處設置第二個時間戳,旋轉角度為17度,最後在尾巴新增跟開始一樣的0度,要讓手回到原本的位置。這樣就能完成基本的揮手動作
第二個範例,讓 Dash 可以眨眼。眼睛的部分使用了三個元素去實作,在閉眼時要注意他們的變化時間點,像是眼白的部分就要在眼皮蓋下來時才能變化,動畫才會自然。針對三個元素我在不同時間點設置時間戳,調整 scale,並設置運作時間為 0.25 秒
預設動畫在執行的時候只跑一次,共有三種模式
- One Shot → 跑一次
- Loop → 循環,從頭開始
- Ping Pong → 循環,但是從頭開始,從尾巴回來
時間軸預設為 1 秒,可以自行調整運行時長和速度
State Machine 動畫控制
可以根據自定義的條件、邏輯顯示指定的動畫。
在 Animations 側邊欄,新增一個 State Machine,預設會有 Entry
、Any State
跟 Exit
,幾種狀態,建議可以先新增一個 Idle
狀態,在載入動畫後為 Idle 狀態,等待指定動畫觸發。
此範例我有新增三個動畫,飛行、眨眼和揮手,所以我需要一些狀態變數來控制動畫,在 Inputs 裡新增了 isFlying, isWinking, isWaving 三個 Boolean 值,期望在 APP 裡能透過按鈕來開關以及觸發這些動畫。
對於 Idle 和三個狀態需要產生對應關係,並給予條件,當數值改變時動畫的狀態怎麼更新,最後還能設置離開狀態的時間。Exit Time
可以設置毫秒或是百分比,在一般的情況下會建議設為 100%,意思是等待動畫完全完成後再更改狀態,才不會有卡一半的情況,感覺會很怪
點擊播放後就能直接更新 Inputs,驗證實際互動的感覺。這裡提醒一下,Layer 面板只能跟一個動畫互動,而我這裡使用到兩層,為了在 isWaving 為 true 時,除了能夠觸發原本的揮手動畫,還希望眨眼動畫也一起動作,有更多效果
我在 Layer2 設置當 isWaving 為 true 時觸發眨眼動畫,需要在 Conditions 給予指定條件,還有返回 Idle 狀態的箭頭也記得要設定
提醒:記得不管是 Animation、State Machine 或是繪製的圖形、線條和群組,都要有易讀的命名規則,這樣在程式開發時才會有好的維護性
動畫導出
- 導出本地檔案 → 副檔名為
.riv
。本文範例只有 4kb 的大小 - 導出雲端資源 → 展示連結、嵌入代碼,甚至是 React 的範例代碼
- 提交到 Rive Community 跟大家分享、交流
將我的分享 Flutter Dash 分享到社群,讓有興趣的人可以瀏覽和使用
Flutter Rive 開發
將導出的 .riv
檔案加入 assets 目錄,並記得在 pubspec.yaml
新增對應路徑,APP 才能夠載入
Common Usage
動畫檔裡面包括了 StateMachine 和 Animations,這邊我指定播放 Fly 動畫,讓 Dash 飛起來。這種使用方式就很適合作為 Loading indicator,再資料載入時顯示出來
const AspectRatio(
aspectRatio: 1,
child: RiveAnimation.asset(
'assets/animations/dash.riv',
fit: BoxFit.cover,
animations: ['Fly'],
),
),
State Machine
宣告 Artboard、StateMachineController,還有動畫使用的狀態控制 SMIInput,並在 initState()
進行 Rive 初始化
Artboard? _artboard;
StateMachineController? _stateMachineController;
SMIInput<bool>? _flyInput;
SMIInput<bool>? _waveInput;
SMIInput<bool>? _winkInput;
@override
void initState() {
super.initState();
_initRive();
}
- 首先透過
rootBundle
載入檔案,取得 RiveFile 實體,並透過它取得我們編輯的面板,如果只有一個的話就可以使用mainArtboard
屬性 - 接著取得 StateMachineController,它掌管動畫的生命週期,我們需要它來與動畫互動,告訴它需要連結哪個畫布
- 將自定義的 SMIInput 狀態控制物件記錄下來,責控制動畫參數,更新動畫
void _initRive() {
rootBundle.load('assets/animations/dash.riv').then(
(data) async {
final file = RiveFile.import(data);
final artboard = file.mainArtboard;
final controller = StateMachineController.fromArtboard(artboard, 'State Machine 1');
if (controller != null) {
artboard.addController(controller);
_flyInput = controller.findInput('isFlying');
_waveInput = controller.findInput('isWaving');
_winkInput = controller.findInput('isWinking');
}
_stateMachineController = controller;
_artboard = artboard;
setState(() {});
},
);
}
此範例簡單透過三個按鈕來執行動畫,只需要更新為 true,就能觸發動畫。反之設為 false 就是停止並返回 Idle 狀態
ElevatedButton(
onPressed: () {
_resetToIdle();
setState(() {
_flyInput?.value = !(_flyInput?.value ?? false);
});
},
child: const Text('Fly'),
),
_resetToIdle()
負責重置狀態回 Idle,等待觸發新的動畫
void _resetToIdle() {
_flyInput?.value = false;
_waveInput?.value = false;
_winkInput?.value = false;
setState(() {});
}
Other Effects
更進階的動畫效果還有 Bone,針對人物或是東西可以設置骨頭,代表可以控制所在區塊進行旋轉,例如:人物的腳可以蹲下、人物帶的圍巾可以隨風飄逸,能夠玩出非常多花樣,只要你夠有創意和想法的話
還有 Meshes(網格),針對圖形標示多個區塊,透過原點的移動來實現變形
更多資訊可以查看官方說明
Rive Community
當然 Rive 也有自己的社群,大家都可以將自己的作品分享出去,可以互相學習,我們也能看別人是如何實作一些效果,覺得不錯的話可以直接在 APP 裡使用,不覺得很棒嗎
Conclusion
到這邊大家應該了解 Rive 不少吧,它讓我們很輕鬆的製作動畫,即便團隊缺少 UI 或是動畫設計師,我們也可以透過學習很快地上手,幫公司的 APP 做出開場動畫、載入動畫,設置是與使用者的互動效果,對於開發者來說很友善。官方也很常在 Youtube 頻道進行直播,有例行的團隊會議還有手把手教學,在於社群活躍度來說很健康,加上 Flutter 屢次的推廣與合作,想必 Rive 應該會持續火熱!
它是一個很值得你去了解的產品,未來如果有一些改版或是想法,我都會在 Twitter 和 Medium 分享,也歡迎留言跟我交流討論!
Reference
- 學會運用 Flutter Widgetbook,該管好自己和公司的元件庫了!
- 剛進入 Flutter 嗎?適合初學者食用,GetX 是否適合你呢!
- 教你為 Riverpod 2.0 撰寫 Flutter 測試 part.1
- 教你為 Riverpod 2.0 撰寫 Flutter 測試 part.2
- 輕鬆了解 Isar NoSQL DB,用它來實作 Flutter 資料庫吧!
- Flutter 輕鬆實作 i18n,使用 easy_localization_generator 就對了
- Flutter CICD 使用 Gitlab Runner 和 App Center 實作 part.1
- Flutter CICD 使用 Gitlab Runner 和 App Center 實作 part.2
- 使用 CodeMagic 和 Firebase 實現 Flutter CICD
- 輕鬆完成Flutter開發環境,最新版!
- 實作Flutter多變有趣的滾動效果CustomScrollView!
- 如何在Flutter使用 Makefile 節省你的時間?
- Easily understand StatefulWidget LifeCycle of Flutter
- “freezed” makes model class strong and easily
- 提高Flutter性能的小技巧!(一)
- 提高Flutter性能的小技巧!(二)
- 提高Flutter性能的小技巧!(三)
- What are Async and Isolates in Flutter?
- LoadBalancer is optimization for Isolates in Flutter
- Riverpod 輕鬆學,原來這麼好用!
- Riverpod 輕鬆學(二),一些進階用法!
About
- GitHub: chyiiiiiiiiiiii
- Instagram: flutterluvr.yii
- Linkedin: yiichenhi
- Youtube: Yii
- Youtube: 一起饅頭(美食頻道)
- Email: ab20803@gmail.com
Contribution
如果覺得文章不錯的話可以贊助,讓我有更多動力和熱情分享學習紀錄和生活!請我喝一杯咖啡吧~
希望有幫助到你/妳,歡迎追蹤我,方便瀏覽最新的文章~