Flutter 淺嘗 Flare / Lottie / SVGA 多種動畫模式

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    動畫在應用中是非常常見的,","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Flutter","attrs":{}},{"type":"text","text":" 不僅提供了多種 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Animated","attrs":{}},{"type":"text","text":" 相關的動畫模式,還支持多種三方的動畫模式,和尚今天嘗試一下 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Flare / Lottie / SVGA","attrs":{}},{"type":"text","text":" 三種動畫模式;","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"Flare","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Flare","attrs":{}},{"type":"text","text":" 是 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Flutter","attrs":{}},{"type":"text","text":" 的動畫插件名稱,全名是 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"flare_flutter","attrs":{}},{"type":"text","text":";","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Flare","attrs":{}},{"type":"text","text":" 可以爲 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"App","attrs":{}},{"type":"text","text":"/遊戲/網頁等製作酷炫的矢量動畫模型;","attrs":{}},{"type":"link","attrs":{"href":"https://rive.app/about-rive/","title":"","type":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Rive","attrs":{}}]},{"type":"text","text":" 是製作 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Flare","attrs":{}},{"type":"text","text":" 動畫的網站,在這裏不僅可以自由定製動畫,還可以免費下載大量開源的優秀動畫;","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Flare","attrs":{}},{"type":"text","text":" 動畫的優勢是有效減少文件體積且獲取極好的動畫效果,適用於與場景交互不大的場景;","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"1. 初識 Flare","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    和尚剛開始學習 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Flare","attrs":{}},{"type":"text","text":",官網註冊賬號成功後,便可以訪問 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Nima","attrs":{}},{"type":"text","text":" 和 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Flare","attrs":{}},{"type":"text","text":" 文件,","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Flare","attrs":{}},{"type":"text","text":" 動畫包括兩種;官網對於不同類型的資源有不同圖標區分;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Nima","attrs":{}},{"type":"text","text":" 爲較舊格式,僅支持光柵圖;主要是爲遊戲引擎和應用構建 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"2D","attrs":{}},{"type":"text","text":" 動畫;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Flare","attrs":{}},{"type":"text","text":" 爲較新格式,支持矢量圖與光柵圖;主要爲 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"App","attrs":{}},{"type":"text","text":" 和 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Web","attrs":{}},{"type":"text","text":" 構建高效動畫,也可用於遊戲設計;","attrs":{}}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/69/69aab85fd94600ba4770ad24ead3ab31.png","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    對於動畫的製作過程,和尚暫不介紹,一是每個人的使用不同,二是和尚也在摸索過程,設計一個滿意的動畫需要精心設計與調整;資源區分公開和私有版,可根據右下角是否有 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"follow","attrs":{}},{"type":"text","text":" 箭頭區分,和尚僅嘗試一下開源的動畫;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/b4/b45f4b013174062919504abed3013d5b.png","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    和尚選擇一個開源的動畫進入詳情頁,可以在 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"open in flutter","attrs":{}},{"type":"text","text":" 中進行自定義調整;可以添加或處理資源樣式動畫的貝塞爾曲線等,同時根據需求處理是否循環播放,可減少代碼中處理;","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/e4/e429e394a458c46e4624bd7c30072651.png","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/2a/2a2fcc05707e17b0e65a16380bcffdb9.png","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"2. 集成方式","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    和尚嘗試的是 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Flare","attrs":{}},{"type":"text","text":" 格式的動畫,將 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":".flr","attrs":{}},{"type":"text","text":" 動畫資源添加到本地資源庫 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"images","attrs":{}},{"type":"text","text":" 中;若使用的是 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Nima","attrs":{}},{"type":"text","text":" 格式的動畫資源,可以嘗試 ","attrs":{}},{"type":"link","attrs":{"href":"https://pub.dev/packages/nima","title":"","type":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"nima","attrs":{}}]},{"type":"text","text":" 插件;","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"1. pubspec.yaml 中添加依賴庫","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"dependencies:\n flare_flutter: ^1.5.2\n","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"2. 在文件中添加引用庫","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"import \"package:flare_flutter/flare_actor.dart\";\n","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"3. API 調用實現","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    插件中提供了方便的 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Widget","attrs":{}},{"type":"text","text":" 可以方便調用;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"FlareActor('images/flare_boll.flr', animation: 'Bounce')\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"分析源碼:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"const FlareActor(this.filename,\n {this.boundsNode,\n this.animation,\n this.fit = BoxFit.contain,\n this.alignment = Alignment.center,\n this.isPaused = false,\n this.snapToEnd = false,\n this.controller,\n this.callback,\n this.color,\n this.shouldClip = true});\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"filename","attrs":{}},{"type":"text","text":" 用來加載本地動畫資源;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"animation","attrs":{}},{"type":"text","text":" 爲製作動畫過程中動畫名稱,且區分大小寫,所以建議在編輯動畫時動畫名稱更明確,若沒有 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"animation","attrs":{}},{"type":"text","text":" 參數或內容有誤,最終展示的時動畫的第一幀;","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/53/53ac459c3d8af64c7f9f225edc6f1fa2.png","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"fit","attrs":{}},{"type":"text","text":" 動畫填充樣式;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"alignment","attrs":{}},{"type":"text","text":" 動畫對齊方式;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"isPause","attrs":{}},{"type":"text","text":" ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"true","attrs":{}},{"type":"text","text":" 爲暫停,","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"false","attrs":{}},{"type":"text","text":" 爲繼續;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"snapToEnd","attrs":{}},{"type":"text","text":" ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"true","attrs":{}},{"type":"text","text":" 爲直接跳到動畫最後一幀,","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"false","attrs":{}},{"type":"text","text":" 爲正常播放;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"color","attrs":{}},{"type":"text","text":" 動畫顏色,若整體顏色爲純色可嘗試使用,否則會覆蓋其他設計顏色;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"controller","attrs":{}},{"type":"text","text":" 控制器,可以通過 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"controller","attrs":{}},{"type":"text","text":" 控制動畫的播放暫停或到具體的動畫結點等,靈活方便;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"callback","attrs":{}},{"type":"text","text":" 動畫播放完成的回調;當動畫設置的是循環播放則無法監聽;當動畫爲非循環模式時,播放完成第一遍後可監聽結果;和尚測試若再次 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"play('animation')","attrs":{}},{"type":"text","text":" 時動畫會重新播放一次,不會一直循環重複,該監聽方法只有一次;","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"class _FlareStatePage extends State {\n FlareControls _controls = FlareControls();\n bool isPause = false, snapToEnd = false;\n\n @override\n Widget build(BuildContext context) {\n return Scaffold(\n body: Column(children: [\n Expanded(\n child: FlareActor('images/flare_question.flr',\n animation: 'default',\n alignment: Alignment.center,\n fit: BoxFit.contain,\n controller: _controls,\n isPaused: isPause,\n snapToEnd: snapToEnd, callback: (name) {\n if (name == 'default') {\n _controls.play('default');\n }\n }),\n flex: 1),\n Row(children: [\n _itemBtn('start'), _itemBtn('pause'), _itemBtn('resume'), _itemBtn('stop')\n ]),\n Expanded(\n child: Column(children: [\n Expanded( child: FlareActor('images/flare_boll.flr', animation: 'Bounce')),\n Expanded( child: FlareActor('images/flare_boll.flr', animation: 'Bounce', color: Colors.orange))\n ]),\n flex: 1)\n ]));\n }\n\n Widget _itemBtn(str) {\n return Expanded(\n child: Container(\n margin: EdgeInsets.all(1.0),\n child: FlatButton(\n color: Colors.lightBlueAccent,\n child: Text(str),\n onPressed: () {\n if (str == 'start') {\n isPause = false;\n snapToEnd = false;\n _controls.play('default');\n } else if (str == 'pause') {\n isPause = true;\n } else if (str == 'resume') {\n isPause = false;\n } else if (str == 'stop') {\n snapToEnd = true;\n }\n setState(() {});\n })));\n }\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/77/77311e1a77dbc50621824d3338d319c4.gif","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"Lottie","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    ","attrs":{}},{"type":"link","attrs":{"href":"http://airbnb.io/lottie/#/","title":"","type":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Lottie","attrs":{}}]},{"type":"text","text":" 在 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Android","attrs":{}},{"type":"text","text":" 和 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"iOS","attrs":{}},{"type":"text","text":" 中的應用非常廣泛,同時也支持 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Flutter","attrs":{}},{"type":"text","text":" 等平臺,和尚在官網查詢之後發現官網推薦了兩個開源的 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Lottie","attrs":{}},{"type":"text","text":" 插件,和尚對其中的 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"https://github.com/simolus3/fluttie","attrs":{}},{"type":"text","text":" 進行學習嘗試;","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/d0/d0fa514f20d429e5bd5758db2f97caac.png","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    和尚首先在 ","attrs":{}},{"type":"link","attrs":{"href":"https://lottiefiles.com","title":"","type":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"lottiefiles","attrs":{}}]},{"type":"text","text":" 中下載了兩個酷炫的動畫 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"json","attrs":{}},{"type":"text","text":",我們也可以選擇合適的動畫進行編輯調整;跟原生一樣,可以隨心設計,當然這項重任還是要交給視覺設計的小姐姐比較好;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/97/97de4c7ba9649af093e3f247bd69611a.png","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"1. 集成方式","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    集成方式都是統一的三大步驟;再此之前可以將下載的 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"json","attrs":{}},{"type":"text","text":" 文件添加到本地 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"images","attrs":{}},{"type":"text","text":" 資源文件夾中;","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"1. 在 pubspec.yaml 中添加依賴庫","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"dependencies:\n fluttie: ^0.3.2\n","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"2. 在文件中添加引用庫","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"import 'package:fluttie/fluttie.dart';\n","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"3. 根據 API 調用","attrs":{}}]},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"通過 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"loadAnimationFromAsset","attrs":{}},{"type":"text","text":" 異步加載本地 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"json","attrs":{}},{"type":"text","text":" 資源,或通過 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"loadAnimationFromJson","attrs":{}},{"type":"text","text":" 直接加載 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"json","attrs":{}},{"type":"text","text":" 內容;","attrs":{}}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"void prepareLottie() async {\n var instance = Fluttie();\n var whaleLottie = await instance.loadAnimationFromAsset('images/animation_demo01.json');\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":2,"normalizeStart":2},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"設置 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"FluttieAnimationController","attrs":{}},{"type":"text","text":" 控制器,綁定動畫資源,並設置動畫的基本屬性;","attrs":{}}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"prepareAnimation","attrs":{}},{"type":"text","text":" 的固定參數是動畫資源,不可缺少;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"repeatCount","attrs":{}},{"type":"text","text":" 可設置動畫重複的頻率;","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"RepeatCount.nTimes(n)","attrs":{}},{"type":"text","text":" 重複 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"n+1","attrs":{}},{"type":"text","text":" 次;","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"RepeatCount.infinite()","attrs":{}},{"type":"text","text":" 無限循環播放;","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"RepeatCount.dontRepeat()","attrs":{}},{"type":"text","text":" 僅一次,播放完停止;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"repeatMode","attrs":{}},{"type":"text","text":" 可設置動畫播放模式,","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"START_OVER","attrs":{}},{"type":"text","text":" 播放完從頭再次播放,","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"REVERSE","attrs":{}},{"type":"text","text":" 從無到有從有到無;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"duration","attrs":{}},{"type":"text","text":" 可設置動畫播放時長;當設置無限重複時不生效;其餘根據重複頻率使單次動畫時長均分;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"preferredSize","attrs":{}},{"type":"text","text":" 可設置動畫預加載大小,並不直接控制 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Widget","attrs":{}},{"type":"text","text":" 大小;","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"whaleController = await instance.prepareAnimation(\n whaleLottie,\n repeatCount: const RepeatCount.infinite()\n);\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":3,"normalizeStart":3},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"開啓動畫即可準備好動畫的基本要素;","attrs":{}}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"setState(() { whaleController.start(); });\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":4,"normalizeStart":4},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"將動畫繪製在 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Widget","attrs":{}},{"type":"text","text":" 即可初步成功;","attrs":{}}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"@override\nWidget build(BuildContext context) {\n return Scaffold(\n body: Center(\n child: Column(mainAxisSize: MainAxisSize.min, children: [\n Container( width: 280.0, height: 200.0,\n child: FluttieAnimation(whaleController))\n )\n ])));\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":5,"normalizeStart":5},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":5,"align":null,"origin":null},"content":[{"type":"text","text":"我們也可以動態監聽動畫狀態並進行處理;","attrs":{}}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"start()","attrs":{}},{"type":"text","text":" 從頭開啓動畫;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"pause()","attrs":{}},{"type":"text","text":" 暫停動畫;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"unpause()","attrs":{}},{"type":"text","text":" 從暫停處繼續播放動畫;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"stopAndReset()","attrs":{}},{"type":"text","text":" 停止動畫,","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"rewind","attrs":{}},{"type":"text","text":" 爲 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"true","attrs":{}},{"type":"text","text":" 時結束動畫併到動畫開始時第一幀;","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"false","attrs":{}},{"type":"text","text":" 爲技術動畫併到動畫最後一幀;","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"Row(children: [\n Expanded( flex: 1,\n child: FlatButton(\n onPressed: () { starController.start(); },\n child: Text('start'))),\n Expanded( flex: 1,\n child: FlatButton(\n onPressed: () { starController.pause(); },\n child: Text('pause'))),\n Expanded( flex: 1,\n child: FlatButton(\n onPressed: () { starController.unpause(); },\n child: Text('resume'))),\n Expanded( flex: 1,\n child: FlatButton(\n onPressed: () { starController.stopAndReset(rewind: true); },\n child: Text('stop')))\n])\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/7f/7fb703cf81317f7d9a9c499082c8138a.jpeg","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"2. 注意事項","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"1. ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"dispose()","attrs":{}},{"type":"text","text":" 動畫","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    動畫對應用內存佔用較大,建議在頁面銷燬或關閉時將動畫銷燬;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"@override\nvoid dispose() {\n super.dispose();\n whaleController?.dispose();\n starController?.dispose();\n}\n","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"2. dispose() 與 stopAndReset() 區別","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"stopAndReset()","attrs":{}},{"type":"text","text":" 方法用來控制動畫的停止狀態,資源依然存在內存中,之後可繼續操作動畫的狀態;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"dispose()","attrs":{}},{"type":"text","text":" 方法用來停止動畫並釋放資源,之後不能再操作動畫狀態;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"class _LottieStatePage extends State {\n FluttieAnimationController whaleController, starController;\n\n @override\n Widget build(BuildContext context) {\n return Scaffold(\n body: Center(\n child: Column(mainAxisSize: MainAxisSize.min, children: [\n Container(\n width: 280.0,\n height: 200.0,\n child: FluttieAnimation(whaleController)),\n Container(child: FluttieAnimation(starController)),\n Row(children: [\n Expanded(\n flex: 1,\n child: FlatButton(\n onPressed: () {\n starController.start();\n },\n child: Text('start'))),\n Expanded(\n flex: 1,\n child: FlatButton(\n onPressed: () {\n starController.pause();\n },\n child: Text('pause'))),\n Expanded(\n flex: 1,\n child: FlatButton(\n onPressed: () {\n starController.unpause();\n },\n child: Text('resume'))),\n Expanded(\n flex: 1,\n child: FlatButton(\n onPressed: () {\n starController.stopAndReset(rewind: false);\n },\n child: Text('stop')))\n ])\n ])));\n }\n\n @override\n void dispose() {\n super.dispose();\n whaleController?.dispose();\n starController?.dispose();\n }\n\n @override\n void initState() {\n super.initState();\n prepareLottie();\n }\n\n void prepareLottie() async {\n var instance = Fluttie();\n var whaleLottie =\n await instance.loadAnimationFromAsset('images/animation_demo01.json');\n whaleController = await instance.prepareAnimation(\n whaleLottie,\n repeatCount: const RepeatCount.nTimes(2));\n\n var starLottie = await instance.loadAnimationFromAsset('images/star.json');\n starController = await instance.prepareAnimation(starLottie,\n repeatCount: const RepeatCount.infinite(),\n repeatMode: RepeatMode.START_OVER);\n\n setState(() {\n whaleController.start();\n starController.start();\n });\n }\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/3c/3c862fba1ddffb1539ee6a89ee728258.gif","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"SVGA","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    和尚之前嘗試了 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Flare","attrs":{}},{"type":"text","text":" 和 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Lottie","attrs":{}},{"type":"text","text":" 動畫,實現效果都很高效;今天和尚嘗試另一種思路 ","attrs":{}},{"type":"link","attrs":{"href":"http://svga.io/index.html","title":"","type":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"SVGA","attrs":{}}]},{"type":"text","text":" 動畫;","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"SVGA","attrs":{}},{"type":"text","text":" 是一種同時兼容 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"iOS / Android / Flutter / Web","attrs":{}},{"type":"text","text":" 多個平臺的動畫格式;","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"1. 基本簡介","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    和尚首先讚美一下 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"SVGA","attrs":{}},{"type":"text","text":" 官網,非常簡潔而且主要信息都容易查到,同時看着非常舒服;設計師通過 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"AE","attrs":{}},{"type":"text","text":" 等工具設計生成好 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"SVGA","attrs":{}},{"type":"text","text":" 動畫後,可直接交付給開發同學通過 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"SVGAPlayer","attrs":{}},{"type":"text","text":" 直接調用即可,集成和應用都很簡單;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"SVGA","attrs":{}},{"type":"text","text":" 提供了在線動畫素材預覽以及素材元素拆分,還可以將 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"SVGA","attrs":{}},{"type":"text","text":" 動畫轉化爲 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"SVG","attrs":{}},{"type":"text","text":" 矢量圖元素,非常靈活方便;","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/be/be46bb424d249943f446a69d7076ae76.png","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/46/46728a1dd932114b0c825451ceb7a580.png","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/db/dbe98f778ed4bc59c166ec48f0f529ab.png","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"2. 案例嘗試","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"SVGA","attrs":{}},{"type":"text","text":" 提供了多種方式完整的集成方案,和尚簡單嘗試一下 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Flutter","attrs":{}},{"type":"text","text":" 版本應用;","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"1. 集成 svgaplayer_flutter","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    與所有插件使用相同,和尚引入對應版本的 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"svgaplayer_flutter","attrs":{}},{"type":"text","text":";目前 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"svgaplayer_flutter","attrs":{}},{"type":"text","text":" 已支持 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Flutter 2.0","attrs":{}},{"type":"text","text":" 空安全;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"svgaplayer_flutter: ^2.1.2\n","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"2. 應用播放 SVGA","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"2.1 SVGASimpleImage 加載動畫","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"svgaplayer_flutter","attrs":{}},{"type":"text","text":" 支持播放本地動畫和網絡線上動畫,與 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Image","attrs":{}},{"type":"text","text":" 加載本地和網絡圖片類似;","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"SVGA","attrs":{}},{"type":"text","text":" 提供了封裝好 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"SVGAAnimationController","attrs":{}},{"type":"text","text":" 控制器的 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"SVGASimpleImage","attrs":{}},{"type":"text","text":";根據文件類型,通過不同參數進行展示,默認動畫效果爲重複播放;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"class SVGASimpleImage extends StatefulWidget {\n final String resUrl;\n final String assetsName;\n final File file;\n\n SVGASimpleImage({Key key, this.resUrl, this.assetsName, this.file}) : super(key: key);\n\n @override\n State createState() => _SVGASimpleImageState();\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    簡單分析源碼可得,","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"SVGASimpleImage","attrs":{}},{"type":"text","text":" 根據傳遞的不同動畫路徑進行不同方式的展示,通過 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"SVGAParser.shared","attrs":{}},{"type":"text","text":" 加載和解碼不同類型的網絡資源、本地資源以及 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"File","attrs":{}},{"type":"text","text":" 資源等;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"class _SVGAPageState extends State {\n @override\n Widget build(BuildContext context) {\n return Scaffold(\n appBar: AppBar(title: Text('SVGA Page')),\n body: Column(children: [\n _itemSVGA01(false, 'images/posche.svga'),\n _itemSVGA01(true, 'https://github.com/yyued/SVGA-Samples/blob/master/angel.svga?raw=true')\n ]));\n }\n\n _itemSVGA01(isUrl, svgaUrl) {\n return Expanded( flex: 1,\n child: SVGASimpleImage(assetsName: isUrl ? null : svgaUrl, resUrl: isUrl ? svgaUrl : null));\n }\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/e1/e19157db3e9a307ed4cbff43040c29df.gif","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"2.2 SVGAImage & SVGAAnimationController","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"SVGASimpleImage","attrs":{}},{"type":"text","text":" 是將 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"SVGAImage","attrs":{}},{"type":"text","text":" 和 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"SVGAAnimationController","attrs":{}},{"type":"text","text":" 封裝好的動畫播放器,若我們想自由控制動畫的播放、暫停、重播等操作的話,需要配合 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"SVGAAnimationController","attrs":{}},{"type":"text","text":" 控制器調節動畫的播放過程;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"SVGAImage(\n this._controller, {\n this.fit = BoxFit.contain,\n this.clearsAfterStop = true,\n})\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    簡單分析源碼可得,","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"SVGAImage","attrs":{}},{"type":"text","text":" 主要是通過 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"SVGAAnimationController","attrs":{}},{"type":"text","text":" 來進行動畫播放;與圖片類似,可以通過 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"BoxFit","attrs":{}},{"type":"text","text":" 設置動畫的佈局樣式;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"SVGAAnimationController","attrs":{}},{"type":"text","text":" 是對 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"AnimationController","attrs":{}},{"type":"text","text":" 進一層封裝與應用,調用的方法和狀態回調基本是一致的;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"enum AnimationStatus {\n /// 動畫開始時結束\n dismissed,\n\n /// 動畫開始\n forward,\n\n /// 逆向動畫\n reverse,\n\n /// 動畫完成結束\n completed,\n}\n\nthis.animationController ?.addStatusListener((status) => print('---status---$status'));\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"SVGAAnimationController","attrs":{}},{"type":"text","text":" 提供了常用的播放方法,和尚簡單嘗試幾種常用的;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"reset","attrs":{}},{"type":"text","text":" 動畫重置;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"forward","attrs":{}},{"type":"text","text":" 動畫播放,和尚建議若動畫從頭開始播放先調用 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"reset","attrs":{}},{"type":"text","text":" 使動畫重置,防止其他操作影響動畫起始位置;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"stop","attrs":{}},{"type":"text","text":" 動畫停止,與 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Lottie","attrs":{}},{"type":"text","text":" 動畫不同,","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"SVGAAnimationController","attrs":{}},{"type":"text","text":" 沒有提供對應的暫停方法,和尚將 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"stop","attrs":{}},{"type":"text","text":" 理解爲暫停和停止,若繼續播放則調用 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"forward","attrs":{}},{"type":"text","text":" 即可;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"reverse","attrs":{}},{"type":"text","text":" 動畫反轉,即反向播放動畫;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"repeat","attrs":{}},{"type":"text","text":" 動畫重複;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"fling","attrs":{}},{"type":"text","text":" 使用臨界阻尼彈簧和初始速度驅動動畫;和尚簡單理解在正向播放時,","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"fling","attrs":{}},{"type":"text","text":" 會按起始速度播放完成;","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"@override\nvoid initState() {\n super.initState();\n this.animationController = SVGAAnimationController(vsync: this)\n ..addListener(() {\n if (mounted) { setState(() {}); }\n });\n this._loadAnimation();\n}\n\n@override\nvoid dispose() {\n this.animationController?.clear();\n this.animationController?.dispose();\n this.animationController = null;\n super.dispose();\n}\n\nvoid _loadAnimation() async {\n final videoItem = await _loadSVGA(false, 'images/posche.svga');\n if (mounted)\n setState(() {\n this.isLoading = false;\n this.animationController?.videoItem = videoItem;\n this.animationController ?.addStatusListener((status) => print('---status---$status'));\n });\n}\n\nWidget _itemBtn(str) => Expanded(\n child: Container(\n margin: EdgeInsets.all(1.0),\n child: FlatButton(\n color: Colors.lightBlueAccent,\n child: Text(str),\n onPressed: () {\n if (str == 'start') {\n animationController?.reset();\n animationController?.forward();\n } else if (str == 'reverse') {\n animationController?.reverse();\n } else if (str == 'repeat') {\n animationController?.repeat();\n } else if (str == 'resume') {\n animationController?.forward();\n } else if (str == 'stop') {\n animationController?.stop();\n } else if (str == 'fling') {\n animationController?.fling();\n }\n setState(() {});\n })));\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/30/304719be3c0c5aa7ea918998194b50d7.gif","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"小結","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Flare","attrs":{}},{"type":"text","text":" 動畫是 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Google","attrs":{}},{"type":"text","text":" 力薦的一種動畫模式,對於複雜動畫或遊戲處理,快速而高效,和尚測試內存狀況良好;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"SVGA","attrs":{}},{"type":"text","text":" 是將 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"SVGA","attrs":{}},{"type":"text","text":" 矢量圖逐幀繪製,通過設置幀率,來生成一個配置文件,使得每一幀都有一個配置,每一幀都是關鍵幀,通過幀率去刷每一幀的畫面,這個思路跟 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"GIF","attrs":{}},{"type":"text","text":" 很像,但是通過配置使得動畫過程中圖片都可以得到複用;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"     ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Lottie","attrs":{}},{"type":"text","text":" 動畫是逐層繪製,將所有的動畫拆成多個層級,每個層級 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"layer","attrs":{}},{"type":"text","text":" 都有一個動畫配置,播放時解析多 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"0","attrs":{}},{"type":"text","text":" 個 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"layer","attrs":{}},{"type":"text","text":" 的配置,並給每個 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"layer","attrs":{}},{"type":"text","text":" 做相應的動畫;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    這三種動畫模式都非常成熟且應用範圍廣泛,可以進行實際項目進行具體的選型,和尚對三種動畫的研究還不夠深入,如又錯誤,請多多指導!","attrs":{}}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"【簽約作者第二季】","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"來源: 阿策小和尚","attrs":{}}]}],"attrs":{}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章