HarmonyOS 鸿蒙Next中Lottie动画在列表中滚动卡顿如何优化

HarmonyOS 鸿蒙Next中Lottie动画在列表中滚动卡顿如何优化

【问题现象】

列表中有Lottie动画,当Lottie动画播放时列表滚动卡顿,当Lottie动画播放结束之后,列表滚动恢复正常。如下图:

点击放大

问题代码如下:

// 使用三方库[@abner](/user/abner)/refresh中的组件ListView构造列表
ListView({
  items: this.array, // 数据源 数组,可以任意类型,自定义对象[],number[],string[]……
  itemLayout: this.itemLayout, // 转成你需要的对象
  listAttribute: (attr) => {
    attr.edgeEffect = EdgeEffect.Spring // 设置阻尼效果
  }
})

/**
 * Describe:条目布局
 * @param item  数据对象
 * @param index  数据索引
 */
@Builder
itemLayout(): void {
  Row() {
    AnimatorLottieBase({
      imagePath: "lottie/round_frame95/images/",
      path: "lottie/round_frame95/data.json",
      animateName: 'https://ali-dev-system.lrscloud3.com/avatarframe/round_frame95.zip',
      autoplay: true,
      loop: true,   // 当loop为true时,滚动异常卡顿
    })
      .height(50)
      .width(50)
    Blank(100)
  }
}

【背景知识】

  • Lottie是一个适用于OpenHarmony的动画库,它可以解析Adobe After Effects软件通过Bodymovin插件导出的JSON格式的动画,并在移动设备上进行本地渲染;
  • 卡顿是一种在视觉上表现为画面不流畅、停顿或延迟的现象,它可能由多种因素引起,丢帧是其中一个重要原因;当设备性能不足时,可能无法及时处理和渲染所有的帧,从而导致丢帧,进而引发卡顿。

【定位思路】

1. 用户同一时间加载过多动画,导致性能过载

观察到界面中的Lottie动画数量很多,通过日志打印发现进入动画界面时会初始化多个动画,这样的定义方式会将统一渲染服务进程占满,导致进程在刚进入该界面时不仅要处理动画的初始化,还要处理List列表的滑动,这时设备性能不足,从而丢帧引发卡顿。

2. 多余的动画渲染没有及时销毁,造成不必要的性能损耗

该界面同时加载了多个动画,显示在界面中的15个动画在播放,其余30+个在界面之外的动画也同时在播放。

【解决方案】

1. 合理使用动画生命周期,在首次进入界面时,不过多初始化构造多余动画

上文发现使用ListView会在首次进入界面时构造全部数量(50)的动画,造成性能过载。使用List组件替代三方库@abner/refresh中的组件ListView后,通过日志可以看到首次进入只构造了在界面中显示的14个,随着慢慢向下滑动屏幕,使下方的动画进入界面内,List组件才会构造该动画,卡顿现象得到缓解

代码示例如下:

List({ space: 10, initialIndex: 0 }) { // list上下树逻辑,ondisappear在出界面不会走;api13有需求做;
  ForEach(this.array, (item: number) => {
    ListItem() {
      AnimatorLottieBase({
        imagePath: "lottie/round_frame95/images/",
        path: "lottie/round_frame95/data.json",
        animateName: 'https://ali-dev-system.lrscloud3.com/avatarframe/round_frame95.zip',
        autoplay: false,
        loop: true,   // 当loop为true时,滚动异常卡顿
        index: item,
      })
        .height(50)
        .width(50)
    }
  }, (item: string) => item)
}.width('90%')
.scrollBar(BarState.Off)

2. 动画滑出界面时,控制动画暂停,降低性能损耗

给画布组件添加onVisibleAreaChange属性,当该组件不可见时暂停该动画,可见时播放该动画。

代码示例如下:

.onVisibleAreaChange([0.0, 1.0],
  (isVisible: boolean, currentRatio: number) => {
    if (isVisible) {
      console.log('onVisibleAreaChange:' + 'play' + ' index: ' + this.index)
      this.animationItem?.play();
    } else {
      console.log('onVisibleAreaChange:' + 'stop' + ' index: ' + this.index)
      this.animationItem?.stop();
    }
  })

【总结】

  1. 通过上文两步的调整,卡顿现象在基本场景下已经得到解决;该界面可共同展示多个循环播放的lottie动画,可满足大部分应用场景。
  2. 处理丢帧问题一般需要以下四个步骤:

1. 识别卡顿

首先使用AppAnalyzer检测应用是否存在性能问题,如果检测存在丢帧问题,然后使用Frame Profiler、SmartPerf Host等工具录制Trace,查看应用平均帧率、丢帧率等,同时查看丢帧发生的位置。

2. 分析丢帧原因

可以通过分析Trace,查看卡顿帧的详细信息。最后查看函数调用栈,查看是否存在耗时函数。

3. 选择优化方案

根据步骤分析的丢帧原因,选择适合的优化方案。

4. 验证优化效果

优化完成后需要重新测试验证丢帧问题是否得到解决,这里可以再次通过以上步骤来确认优化效果。


更多关于HarmonyOS 鸿蒙Next中Lottie动画在列表中滚动卡顿如何优化的实战教程也可以访问 https://www.itying.com/category-93-b0.html

1 回复

更多关于HarmonyOS 鸿蒙Next中Lottie动画在列表中滚动卡顿如何优化的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


  1. 使用List组件替代ListView,减少首次进入界面时动画的初始化数量,仅构造当前可见的动画。
  2. 为动画组件添加onVisibleAreaChange属性,当动画滑出界面时暂停播放,滑入界面时继续播放,降低性能损耗。
回到顶部