小程序中使用 lottie 動畫 | 踩坑經驗分享

最近被拉去支援緊急需求(趕在五一節假日前上線的,雙休需要加班😱),參與到項目中才知道,開發的項目是微信小程序技術棧的。由於是臨時支援,筆者也很久沒開發過微信小程序了,所以挑選了相對獨立,業務屬性相對輕薄的模塊參與。

其中有個營銷活動(領紅包🧧😁)的彈窗動畫就要用到 lottie 動畫。

本文就分享一下在小程序中使用 lottie 過程中遇到的問題與解決辦法。

關於 lottie

lottie 是 Airbnb 開源的一個動畫庫,用於在端上直接播放 AE ( Adobe After Effects)動畫。

通過 bodymovin AE 插件將動畫文件導出爲 json 文件,lottie SDK 通過可以通過 JSON 文件直接播放動畫。

具體 demos 效果可以上 LottieFiles 網站查看。

如何使用 AE 導出動畫需要的JSON文件

完成 AE 軟件安裝後,參照 Lottie Web GitHub 官方文檔 完成 bodymovin 插件的安裝。

打開動畫文件後,只需簡單幾步操作

① window 中選擇 Bodymovie

② 選擇需要導出的動畫資源

③ 導出配置(小程序相關)

點擊對應動畫的設置

勾選 Glyphs 將用到的文字+字體導出爲圖形。

小程序裏渲染不支持加載外部字體。

這個就會有 tree shake的效果,如果動畫裏沒有用到的文字,做動態替換的時候就會不顯示,後面會詳細介紹到

勾選 Convert expressions to keyframes 將表達式轉爲關鍵幀,因爲小程序裏不支持使用 eval 等動態執行腳本的能力。

修改完成後點擊Save保存配置。

④ 渲染導出 JSON 文件

最後點擊 Render 按鈕,導出 JSON 文件。

導出文件如下,data.json 文件就是我們需要的 JSON 文件,images 裏存儲的就是播放要用到的圖片文件。

小程序中使用

可以使用小程序官方封裝的 lottie-miniprogram 庫。

快速驗證的話可以打開微信開發者工具,在點擊👉🏻 demo代碼片段 進行創建。

① 安裝依賴

npm install --save lottie-miniprogram

② 使用

tip:開發者工具中驗證的話,渲染模式需要選擇 webview ,Skyline 目前還不支持調試 canvas

index.wxml

<canvas id="lottie-canvas" type="2d"></canvas>

index.js

import lottie from 'lottie-miniprogram'

Page({
  onReady() {
    this.createSelectorQuery().select('#lottie-canvas').node((res) => {
      // 取得 canvas 節點
      const canvas = res[0].node

      // 設置 cavnas 畫布尺寸
      canvas.width = 600
      canvas.height = 600

      lottie.setup(canvas)

      const context = canvas.getContext('2d')
      const lottieInstance = lottie.loadAnimation({
        loop: true, // 循環播放
        autoplay: true, // 自動播放
        // 本地使用 http-server 啓動服務後,指定本地資源地址
        path: 'http://127.0.0.1:8080/lottie-demo-sources/data.json', // 通過http 制定json資源路徑

        // 也可以用下面這種方式,直接傳入 lottie json內容
        // (需要動態替換文案就需要用到這種方式)
        // animationData: {/* lottie json 格式內容 */},
        // 靜態資源目錄,通常與 animationData 配合使用
        // assetsPath: 'http://127.0.0.1:8080/lottie-demo-sources/images/',

        rendererSettings: {
          context,
        },
      })
    }).exec()
  }
})

我這個 demo 的效果(網上找的動畫素材)如下。

問題&解決

下面介紹在實際業務接入使用中遇到的一些問題和解決辦法。

expression 表達式

報錯信息如下,這是遇到的第一個問題(也是上面導出配置中有特別說明的)。

細看了一下文檔,有特別說明,expression 表達式特性是不支持的,因此需要再導出 JSON 文件時禁用相關特性。

解決辦法:導出JSON文件時,禁用掉表達式特性即可。

當然禁用後,JSON 文件大小會有所增加。

比如我這個 demo 從 40kb 增加到了 240kb(當然動畫不一樣,增長的大小會有所不同。有些前後可能只有1-2kb的變化)。

模糊

由於需要全屏展示,動畫文件的尺寸不確定,手動只設置 canvas 尺寸會有模糊的問題。

這個通過掘金搜索了一下就得到了 lottie動畫模糊問題的解決方法

微調一下上面的代碼,就可以解決模糊問題。

const canvas = res[0].node
canvas.width = 600
canvas.height = 600

// 下面是新增的代碼
const dpr = wx.getSystemInfoSync().pixelRatio
canvas.width = canvas.width * dpr
canvas.height = canvas.height * dpr
context.scale(dpr, dpr)

lottie.setup(canvas)

全屏動畫

彈窗的動畫需要全屏展示,因此需要設置 canvas 寬高爲頁面寬高。

index.wxss

#lottie-canvas{
    position: fixed;
    left: 0;
    top: 0;
    width: 100vw;
    height: 100vh;
}

index.js,使用 wx.getSystemInfoSync 獲取設備的信息

const { windowWidth, windowHeight, pixelRatio } = wx.getSystemInfoSync()
canvas.width = windowWidth * pixelRatio
canvas.height = windowHeight * pixelRatio

動態文案

由於是紅包,需要動態展示金額(當然也可能是不固定內容的動態標題)。

思路可以參考這篇文章知乎: 動態修改 Lottie 中的文本

可以使用固定格式的文本 ${文本} 進行替換

// 僞代碼
get('sourceUrl').then((res) => {
  const jsonText = res.data
  const animationData = JSON.parse(jsonText.replace('${金額}', '目標金額'))
})

比如我在 demo 里加一個文字

  • 需要展示的文本里放入 ${num} 用於替換匹配
  • 在添加一個文本藏在看不見的地方,裏面寫入替換後需要用到的文字(確保和上面的文本爲同一種字體)

接着導出 JSON 文件。

調用方法如下

// 拉取JSON文件內容
const jsonData = await new Promise((resolve) => {
  wx.request({
    url: 'http://127.0.0.1:8080/json/text-replace/data.json',
    success: (res) => {
      resolve(res.data)
    }
  })
})

// 隨機生成1-100元的數字,保留兩位小數
const num = (Math.random() * 100).toFixed(2)
// 替換內容
const animationData = JSON.parse(
  JSON.stringify(jsonData)
    .replace(/\$\{num\}/g, `${num}元`)
)

lottie.loadAnimation({
  // 指定json內容
  animationData,
  // 設置依賴的圖片資源位置
  assetsPath: 'http://127.0.0.1:8080/json/text-replace/images/',
  // ...省略其它配置
})

效果如下

style 引發的渲染錯誤

在 canvas 標籤上設置 display控制顯隱,偶現會提示渲染層錯誤。

<canvas style="display:{{show?'block':'none'}}" id="c1" type="2d"></canvas>

解決辦法,給套了一層 view,用wx:if控制咯。

<view  wx:if="{{show}}">
  <canvas id="c1" type="2d"></canvas>
</view>

iOS 播放閃退問題

現象是,非冷啓動小程序的時候,動畫還沒播放完畢就提前結束了。

看代碼log,3s的動畫,播放不到 1s 就觸發了 complete 事件,看現象就是一閃而逝。

const ani = lottie.loadAnimation({
  // 3s 的動畫
  animationData,
  // ...省略其它配置
})

ani.addEventListener('complete', () => {
  console.log('動畫播放結束')
})

解決辦法

TODO:未完待續

最後

時間匆忙,介紹的不是非常的詳細,感興趣的同學可以評論區交流。

demo 完整源碼見 GitHub:lottie-demo

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章