Lottie-前端實現AE動效

項目背景

在海外項目中,爲了優化用戶體驗加入了幾處微交互動畫,實現方式是設計輸出合成的雪碧圖,前端經過序列幀實現動畫效果:
圖片描述
序列幀:
圖片描述
動畫效果:
圖片描述
序列幀:
圖片描述
幀動畫的缺點和侷限性比較明顯,合成的雪碧圖文件大,且在不一樣屏幕分辨率下可能會失真。經調研發現,Lottie是個簡單、高效且性能高的動畫方案。javascript


Lottie是可應用於Android, iOS, Web和Windows的庫,經過Bodymovin解析AE動畫,並導出可在移動端和web端渲染動畫的json文件。換言之,設計師用AE把動畫效果作出來,再用Bodymovin導出相應地json文件給到前端,前端使用Lottie庫就能夠實現動畫效果。
圖片描述css

Bodymovin插件的安裝與使用

  1. 關閉AE
  2. 下載並安裝ZXP installer
    https://aescripts.com/learn/z...
  3. 下載最新版bodymovin插件
    https://github.com/airbnb/lot...
  4. 把下載好的bodymovin.zxp拖到ZXP installer
    圖片描述
  5. 打開AE,在菜單首選項->常規中勾選☑️容許腳本寫入文件和訪問網絡(不然輸出JSON文件時會失敗)
    圖片描述
  6. 在AE中製做動畫,打開菜單窗口->拓展->Bodymovin,勾選要輸出的動畫,並設置輸出文件目錄,點擊render
    圖片描述
    打開輸出目錄會看到生成的JSON文件,若動畫裏導入了外部圖片,則會在images中存放JSON中引用的圖片

前端使用lottie

靜態URL
https://cdnjs.com/libraries/l...html

NPM前端

npm install lottie-web

調用loadAnimationvue

lottie.loadAnimation({
  container: element, // 容器節點
  renderer: 'svg',
  loop: true,
  autoplay: true,
  path: 'data.json' // JSON文件路徑
});

vue-lottie

也能夠在vue中使用lottiejava

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提供了用於監聽動畫執行狀況的事件:node

  • complete
  • loopComplete
  • enterFrame
  • segmentStart
  • config_ready(初始配置完成)
  • data_ready(全部動畫數據加載完成)
  • DOMLoaded(元素已添加到DOM節點)
  • destroy

可以使用addEventListener監聽事件git

// 動畫播放完成觸發
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跳到最後一幀。github

anm.goToAndStop(anm.totalFrames - 1, 1);

這樣的好處是能夠把相關聯的JSON文件合併,經過anm.goToAndPlay控制動畫狀態的切換,以下圖例中一個JSON文件包含了2個動畫狀態的數據:
圖片描述web

圖片資源

JSON文件裏assets設置了對圖片的引用:
圖片描述
若想統一修改靜態資源路徑或者設置成絕對路徑,可在調用loadAnimation時傳入assetsPath參數:

lottie.loadAnimation({
  container: element,
  renderer: 'svg',
  path: 'data.json',
  assetsPath: 'URL'  // 靜態資源絕對路徑
});

功能支持列表

即便用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
圖片描述
試了下的確能夠,以下圖,所以可經過這個方法快速找到須要操做的動畫層,進一步簡化代碼:
圖片描述

小結

  1. Lottie的缺點在於若在AE動畫製做的過程不注意規範,會致使數據文件大、耗內存和性能的問題;Lottie-web的官方文檔不夠詳盡,例如assetsPath參數是在看源碼的時候發現的;開放的API不夠齊全,沒法很靈活地控制動畫層。
  2. 優勢也很明顯,Lottie能幫助提升開發效率,精簡代碼,易於調試和維護;資源文件小,輸出動畫效果保真;跨平臺——Android, iOS, Web和Windows通用。
  3. 總的來講,Lottie的引用能夠替代傳統的GIF和幀動畫,靈活利用好提供的屬性和方法能夠控制動畫的播放,但需注意規範設計和開發的流程,才能夠更高效地完成動畫的製做與調試。
相關文章
相關標籤/搜索