文档管理中心
我的
您当前正在浏览新版开发者文档中心,目录分类和层级有所调整。点击左侧当前文档分类名称前的“☰”图标,可切换文档分类。 了解新版目录
问题处理与运维开发与测试问题应用框架开发UI框架组件使用如何解决页面上大量动效组件导致页面卡顿的问题

如何解决页面上大量动效组件导致页面卡顿的问题

问题现象

页面上存在大量动效组件时,由于频繁的重绘或复杂的渲染操作,导致帧率下降,出现丢帧现象,影响用户体验。如何解决该问题?

问题代码示例参考如下:

收起
自动换行
深色代码主题
复制
  1. @Entry
  2. @Component
  3. struct Index {
  4. @State imageAngle: number = 0
  5. arr: number[] = Array.from(Array(100), (item: number) => {
  6. return item
  7. })
  8. // 定义动画组件
  9. @Builder
  10. windmill() {
  11. Stack() {
  12. Image($r('app.media.startIcon')).width(50).height(50) // 'app.media.startIcon'仅作示例,请替换为实际使用的资源
  13. .rotate({ z: 1, angle: this.imageAngle })
  14. // 旋转动画
  15. .onAppear(() => {
  16. this.getUIContext().animateTo({
  17. duration: 1000,
  18. curve: Curve.Linear,
  19. iterations: -1
  20. }, () => {
  21. this.imageAngle = 3600
  22. })
  23. })
  24. }
  25. }
  26. build() {
  27. Column() {
  28. // 使用网格布局,循环渲染动画组件。
  29. Grid() {
  30. ForEach(this.arr, () => {
  31. GridItem() {
  32. this.windmill()
  33. }
  34. })
  35. }.columnsTemplate('1fr 1fr 1fr 1fr 1fr')
  36. }
  37. .height('100%')
  38. .width('100%')
  39. }
  40. }

背景知识

renderGroup是组件通用方法,它代表了渲染绘制的一个组合。其核心功能就是标记组件,在绘制阶段将组件和其子组件的绘制结果进行合并并缓存,以达到复用的效果,从而降低绘制负载。

解决方案

页面上存在大量动效组件时,使用renderGroup解决卡顿,提升动画性能。启用renderGroup后,在绘制阶段将组件和其子组件的绘制结果进行合并并缓存,以达到复用的效果,从而降低绘制负载,优化渲染性能。

  1. 为了满足renderGroup属性的设置要满足父组件统一应用动效,子组件无动效的限制,将动效在父组件上统一实现。
    收起
    自动换行
    深色代码主题
    复制
    1. Stack() {
    2. Image($r('app.media.startIcon')).width(50).height(50); // 'app.media.startIcon'仅作示例,请替换为实际使用的资源
    3. }
    4. // 实现旋转效果
    5. .rotate({ z: 1, angle: this.imageAngle })
    6. // 父组件统一应用动效
    7. .onAppear(() => {
    8. this.getUIContext().animateTo({
    9. duration: 5000,
    10. curve: Curve.Linear,
    11. iterations: -1
    12. }, () => {
    13. this.imageAngle = 3600;
    14. });
    15. })
  2. 在最外层Stack组件上开启renderGroup属性,实现绘制结果进行合并并缓存,以达到复用。
    收起
    自动换行
    深色代码主题
    复制
    1. // 开启renderGroup属性
    2. .renderGroup(true);
  3. 使用网格布局,循环渲染动画组件。
    收起
    自动换行
    深色代码主题
    复制
    1. Grid() {
    2. ForEach(this.arr, () => {
    3. GridItem() {
    4. this.windmill();
    5. }
    6. })
    7. }.columnsTemplate('1fr 1fr 1fr 1fr 1fr');
  4. 完整示例参考如下:
    收起
    自动换行
    深色代码主题
    复制
    1. @Entry
    2. @Component
    3. struct AnimatedRotations {
    4. @State imageAngle: number = 0;
    5. arr: number[] = Array.from(Array(100), (item: number) => {
    6. return item;
    7. });
    8. @Builder
    9. windmill() {
    10. Stack() {
    11. Image($r('app.media.startIcon')).width(50).height(50); // 'app.media.startIcon'仅作示例,请替换为实际使用的资源
    12. }
    13. // 实现旋转效果
    14. .rotate({ z: 1, angle: this.imageAngle })
    15. // 父组件统一应用动效
    16. .onAppear(() => {
    17. this.getUIContext().animateTo({
    18. duration: 5000,
    19. curve: Curve.Linear,
    20. iterations: -1
    21. }, () => {
    22. this.imageAngle = 3600;
    23. });
    24. })
    25. // 开启renderGroup属性
    26. .renderGroup(true);
    27. };
    28. build() {
    29. Column() {
    30. // 使用网格布局,循环渲染动画组件。
    31. Grid() {
    32. ForEach(this.arr, () => {
    33. GridItem() {
    34. this.windmill();
    35. }
    36. })
    37. }.columnsTemplate('1fr 1fr 1fr 1fr 1fr');
    38. }
    39. .height('100%')
    40. .width('100%')
    41. }
    42. }

    效果对比如下:

    展开
      

    优化前

    优化后

    丢帧数与卡顿

常见FAQ

Q:开启renderGroup配置后,页面卡顿效果未解决,可能是什么原因?

A:为了能使renderGroup功能生效,组件存在以下约束:

  • 组件内容固定不变:父组件和其子组件各属性保持固定,不发生变化。
  • 子组件无动效:由父组件统一应用动效,其子组件均无动效。