Lottie - 实现 AE 动效(Bodymovin)
項目背景
在海外項目中,為了優化用戶體驗加入了幾處微交互動畫,實現方式是設計輸出合成的雪碧圖,前端通過序列幀實現動畫效果:
序列幀:
動畫效果:
序列幀:
幀動畫的缺點和局限性比較明顯,合成的雪碧圖文件大,且在不同屏幕分辨率下可能會失真。經調研發現,Lottie是個簡單、高效且性能高的動畫方案。
Lottie是可應用于Android, iOS, Web和Windows的庫,通過Bodymovin解析AE動畫,并導出可在移動端和web端渲染動畫的json文件。換言之,設計師用AE把動畫效果做出來,再用Bodymovin導出相應地json文件給到前端,前端使用Lottie庫就可以實現動畫效果。
Bodymovin插件的安裝與使用
https://aescripts.com/learn/zxp-installer
lottie-web/bodymovin.zxp at master · airbnb/lottie-web · GitHub
打開輸出目錄會看到生成的JSON文件,若動畫里導入了外部圖片,則會在images中存放JSON中引用的圖片
前端使用lottie
靜態URL
lottie-web - Libraries - cdnjs - The #1 free and open source CDN built to make life easier for developers
NPM
npm?install?lottie-web調用 loadAnimation
lottie.loadAnimation({container: element, // 容器節點renderer: 'svg',loop: true,autoplay: true,path: 'data.json' // JSON文件路徑 });vue-lottie
也可以在vue中使用lottie
import lottie from '../lib/lottie';import * as favAnmData from '../../raw/fav.json';export default {props: {options: {type: Object,required: true},height: Number,width: Number,},data () {return {style: {width: this.width ? `${this.width}px` : '100%',height: this.height ? `${this.height}px` : '100%',overflow: 'hidden',margin: '0 auto'}}},mounted () {this.anim = lottie.loadAnimation({container: this.$refs.lavContainer,renderer: 'svg',loop: this.options.loop !== false,autoplay: this.options.autoplay !== false,animationData: favAnmData,assetsPath: this.options.assetsPath,rendererSettings: this.options.rendererSettings});this.$emit('animCreated', this.anim)}}loadAnimation參數
| container | 用于渲染動畫的HTML元素,需確保在調用loadAnimation時該元素已存在 |
| renderer | 渲染器,可選值為'svg'(默認值)/'canvas'/'html'。svg支持的功能最多,但html的性能更好且支持3d圖層。各選項值支持的功能列表在此 |
| loop | 默認值為true。可傳遞需要循環的特定次數 |
| autoplay | 自動播放 |
| path | JSON文件路徑 |
| animationData | JSON數據,與path互斥 |
| name | 傳遞該參數后,可在之后通過lottie命令引用該動畫實例 |
| rendererSettings | 可傳遞給renderer實例的特定設置,具體可看 |
Lottie動畫監聽
Lottie提供了用于監聽動畫執行情況的事件:
- complete
- loopComplete
- enterFrame
- segmentStart
- config_ready(初始配置完成)
- data_ready(所有動畫數據加載完成)
- DOMLoaded(元素已添加到DOM節點)
- destroy
可使用addEventListener監聽事件
// 動畫播放完成觸發 anm.addEventListener('complete', anmLoaded);// 當前循環播放完成觸發 anm.addEventListener('loopComplete', anmComplete);// 播放一幀動畫的時候觸發 anm.addEventListener('enterFrame', enterFrame);控制動畫播放速度和進度
可使用anm.pause和anm.play暫停和播放動畫,調用anm.stop則會停止動畫播放并回到動畫第一幀的畫面。
使用anm.setSpeed(speed)可調節動畫速度,而anm.goToAndStop(value, isFrame)和anm.goToAndPlay可控制播放特定幀數,也可結合anm.totalFrames控制進度百分比,比如可傳anm.totalFrames - 1跳到最后一幀。
這樣的好處是可以把相關聯的JSON文件合并,通過anm.goToAndPlay控制動畫狀態的切換,如下圖例中一個JSON文件包含了2個動畫狀態的數據:
圖片資源
JSON文件里assets設置了對圖片的引用:
若想統一修改靜態資源路徑或者設置成絕對路徑,可在調用loadAnimation時傳入assetsPath參數:
功能支持列表
即使用bodymovin成功輸出了JSON文件(沒有報錯),也會出現動效不如預期的情況,比如這是在AE中構建的形象圖:
但在頁面中渲染效果是這樣的:
這是因為使用了不支持的Merge Paths功能
因此對設計師而言,創建Lottie動畫和往常制作AE動畫有所不同,此文檔記錄了Bodymovin支持輸出的AE功能列表,動畫制作前需跟設計師溝通好,根據動畫加載平臺來確認可使用的AE功能。
除此之外,盡量遵循官方文檔里對設計過程的指導和建議:
- 動畫簡單化。創建動畫時需時刻記著保持JSON文件的精簡,比如盡可能地綁定父子關系,在相似的圖層上復制相同的關鍵幀會增加額外的代碼,盡量不使用占用空間最多的路徑關鍵幀動畫。諸如自動跟蹤描繪、顫動之類的技術會使得JSON文件變得非常大且耗性能。
- 建立形狀圖層。將AI、EPS、SVG和PDF等資源轉換成形狀圖層否則無法在Lottie中正常使用,轉換好后注意刪除該資源以防被導出到JSON文件。
- 設置尺寸。在AE中可設置合成尺寸為任意大小,但需確保導出時合成尺寸和資源尺寸大小保持一致。
- 不使用表達式和特效。Lottie暫不支持。
- 注意遮罩尺寸。若使用alpha遮罩,遮照的大小會對性能產生很大的影響。盡可能地把遮罩尺寸維持到最小。
- 動畫調試。若輸出動畫破損,通過每次導出特定圖層來調試出哪些圖層出了問題。然后在github中附上該圖層文件提交問題,選擇用其他方式重構該圖層。
- 不使用混合模式和亮度蒙版。
- 不添加圖層樣式。
- 全屏動畫。設置比想要支持的最寬屏幕更寬的導出尺寸。
- 設置空白對象。若使用空白對象,需確保勾選可見并設置透明度為0%否則不會被導出到JSON文件。
預覽效果
由于以上所說的功能支持問題會導致輸出動畫效果不確定性,設計師和前端之間有個動畫效果聯調的過程,為了提高聯調效率,設計師可先進行初步的效果預覽,再把文件交付給前端。
方法1:輸出預覽HTML文件
渲染前設置所要渲染的文件
勾選??Demo選項
在輸出的文件目錄中就可找到可預覽的demo.html文件
方法2:LottieFiles分享平臺
把生成的JSON文件傳到LottieFiles平臺,可播放、暫停生成文件的動畫效果,可設置圖層顏色、動畫速度,也可以下載lottie preview客戶端在iOS或Android機子上預覽。
LottieFiles平臺還提供了很多線上公開的Lottie動畫效果,可直接下載JSON文件使用
交互hack
Lottie的不足之處是沒有對應的API操縱動畫層,若想做更細化的動畫處理,只能直接操作節點來實現。比如當播放完左圖動畫進入驚訝狀態后,若想實現右圖隨鼠標移動而控制動畫層的簡單效果:
開啟調試面板可以看到,lottie-web通過使用<g>標簽的transform屬性來控制動畫:
當元素已添加到DOM節點,找到想要控制的<g>標簽,提取其transform屬性的矩陣值,并使用rematrix解析矩陣值。
onIntroDone() {const Gs = this.refs.svg.querySelectorAll('svg > g > g > g');Gs.forEach((node, i) => {// 過濾需要修改的節點...// 獲取transform屬性值const styleArr = node.getAttribute('transform').split(',');styleArr[0] = styleArr[0].replace('matrix(', '');styleArr[5] = styleArr[5].replace(')', '');const style = `matrix(${styleArr[0]}, ${styleArr[1]}, ${styleArr[2]}, ${styleArr[3]}, ${styleArr[4]}, ${styleArr[5]})`;// 使用Rematrix解析const transform = Rematrix.parse(style);this.matrices.push({node,transform,prevTransform: transform});} }監聽鼠標移動,設置新的transform屬性值。
onMouseMove = (e) => {this.mouseCoords.x = e.clientX || e.pageX;this.mouseCoords.y = e.clientY || e.pageY;let x = this.mouseCoords.x - (this.props.browser.width / 2);let y = this.mouseCoords.y - (this.props.browser.height / 2);const diffX = (this.mouseCoords.prevX - x);const diffY = (this.mouseCoords.prevY - y);this.mouseCoords.prevX = x;this.mouseCoords.prevY = y;this.matrices.forEach((matrix, i) => {let translate = Rematrix.translate(diffX, diffY);const product = [matrix.prevTransform, translate].reduce(Rematrix.multiply);const css = `matrix(${product[0]}, ${product[1]}, ${product[4]}, ${product[5]}, ${product[12]}, ${product[13]})`;matrix.prevTransform = product;matrix.node.setAttribute('transform', css);})}進一步優化
看到一個方法,在AE中將圖層命名為#id格式,生成的SVG相應的圖層id會被設置為id,命名為.class格式,相應的圖層class會被設置為class
試了下的確可以,如下圖,因此可通過這個方法快速找到需要操作的動畫層,進一步簡化代碼:
小結
總結
以上是生活随笔為你收集整理的Lottie - 实现 AE 动效(Bodymovin)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 利用SharePoint Designe
- 下一篇: bodymovin导出没有html5,A