文档管理中心
我的
您当前正在浏览新版开发者文档中心,目录分类和层级有所调整。点击左侧当前文档分类名称前的“☰”图标,可切换文档分类。 了解新版目录
指南与API参考指南应用框架ArkUI(方舟UI框架)UI开发 (ArkTS声明式开发范式)使用动画动画效果模糊模糊卡顿问题定位与指导

模糊卡顿问题定位与指导

概述

在应用开发中,动态模糊效果虽然能够增强视觉体验,但不当使用(如对图片组件使用动态模糊、模糊半径过大等)可能导致性能问题,如图像卡顿、丢帧或渲染耗时增加等。这些问题不仅影响用户体验,还可能增加应用的功耗。通过合理优化代码逻辑,可有效降低渲染开销,提升用户体验。本文通过AppAnalyzer工具检测应用中存在的图像模糊卡顿问题,结合工具提示的故障原因,给出相应的优化解决方案,帮助开发者解决图像模糊性能问题。

图像模糊卡顿问题检测和分析

开发者可以通过AppAnalyzer工具对应用的图像模糊性能进行检测,并根据检测报告中的建议进行优化,确保图像模糊性能达标。使用AppAnalyzer工具检测图像模糊性能的步骤如下:

  1. 在DevEco Studio中启动AppAnalyzer工具,详细请参见AppAnalyzer。

  2. 默认选择场景化体检,点击任一手动性能体检项(页面间转场、页面内转场、页面滑动)即可进入对应体检界面。本文以“手动性能页面间转场体检”为例进行说明。

  3. 完成体检后,打开体检报告并点击展开“转场卡顿率”部分。如果检测结果显示黄色或红色警告,且提示“可能故障原因”为“动态模糊绘制丢帧诊断”,则表明存在图像模糊性能问题。

在检测出的图像模糊报告中,若“可能故障原因”为“动态模糊绘制丢帧诊断”,可参考以下两点建议进行优化:

  • 建议对图片组件使用静态模糊
  • 建议缩小模糊半径

图像模糊卡顿问题优化方案

对图片组件使用静态模糊

在使用动态模糊对图片组件进行处理时,若检测结果异常,动态模糊绘制过程中出现丢帧情况。建议改用静态模糊,以优化图片模糊性能。动态模糊与静态模糊的概念及使用场景,请参阅相关文档:使用场景。

例如,从检测报告中的可能故障原因中,点击组件所在源码文件,可跳转定位至TestStructPage.ets页面中的Column组件处。在示例代码中,使用了blur动态模糊API对图片组件进行模糊处理,导致在检测中总耗时过长和丢帧。

反例

收起
自动换行
深色代码主题
复制
  1. Column() {
  2. Image($r('app.media.test'))
  3. .width('100%')
  4. .height('30%')
  5. .objectFit(ImageFit.Auto)
  6. .blur(13)
  7. // ...
  8. }

优化建议

针对图片模糊场景,建议使用静态模糊。通过静态模糊和动态模糊性能效果对比,可以发现在模糊效果类似的条件下,静态模糊的性能要优于动态模糊。建议开发者在组件背景和内容无需实时更新的场景中,优先使用静态模糊,可以减少应用卡顿与丢帧,提升用户体验。

正例

收起
自动换行
深色代码主题
复制
  1. import { image } from '@kit.ImageKit';
  2. import { effectKit } from '@kit.ArkGraphics2D';
  3. import { window } from '@kit.ArkUI';
  4. import { hilog } from '@kit.PerformanceAnalysisKit';
  5. import { BusinessError } from '@kit.BasicServicesKit';
  6. @Component
  7. export struct StaticBlur {
  8. @Consume('navPathStack') navPathStack: NavPathStack;
  9. @State isShowStaticBlur: boolean = false;
  10. @State pixelMap: image.PixelMap | undefined = undefined;
  11. @State imgSource: image.ImageSource | undefined = undefined;
  12. @State bottomSafeHeight: number = 0; // 底部导航栏高度
  13. aboutToAppear(): void {
  14. window.getLastWindow(this.getUIContext().getHostContext()!, (err, windowBar) => {
  15. if (err.code) {
  16. return;
  17. }
  18. try {
  19. // 获取底部导航栏的高度
  20. this.bottomSafeHeight =
  21. this.getUIContext()
  22. .px2vp(windowBar.getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR).bottomRect.height);
  23. } catch (error) {
  24. let err: BusinessError = error as BusinessError;
  25. hilog.warn(0x000, 'testTag', `getWindowAvoidArea failed, code=${err.code}, message=${err.message}`);
  26. }
  27. windowBar.setWindowLayoutFullScreen(true)
  28. .catch((err: BusinessError) => {
  29. hilog.error(0x000, 'testTag', `setWindowLayoutFullScreen failed, code=${err.code}, message=${err.message}`);
  30. })
  31. });
  32. }
  33. aboutToDisappear(): void {
  34. // 在组件销毁时释放pixelMap和imgSource
  35. this.pixelMap?.release();
  36. this.pixelMap = undefined;
  37. this.imgSource?.release();
  38. this.imgSource = undefined;
  39. }
  40. async staticBlur(): Promise<void> {
  41. let context: Context = this.getUIContext().getHostContext()!;
  42. await context.resourceManager.getRawFileContent('test.png') // 从rawfile文件目录中检索图像
  43. .then((fileData: Uint8Array) => {
  44. let buffer: ArrayBuffer = fileData.buffer.slice(0); // 创建一个ArrayBuffer实例
  45. this.imgSource = image.createImageSource(buffer); // 创建ImageSource实例
  46. })
  47. .catch((err: BusinessError) => {
  48. hilog.error(0x000, 'testTag', `getRawFileContent failed, code=${err.code}, message=${err.message}`);
  49. })
  50. // 为pixels创建属性
  51. let opts: image.InitializationOptions = {
  52. editable: true, // 是否可编辑
  53. pixelFormat: 3, // 像素格式,3代表RGBA_8888
  54. size: {
  55. // 创建图像尺寸
  56. height: 4,
  57. width: 6
  58. }
  59. };
  60. // 创建PixelMap
  61. await this.imgSource!.createPixelMap(opts).then((pixelMap: image.PixelMap) => {
  62. const blurRadius: number = 3;
  63. let headFilter: effectKit.Filter = effectKit.createEffect(pixelMap); // 创建Filter实例
  64. if (headFilter !== null) {
  65. headFilter.blur(blurRadius); // 设置静态模糊,将模糊效果添加到效果列表中
  66. // 使用添加了链表效果的PixelMap来检索源图像的图像
  67. headFilter.getEffectPixelMap().then((pixelMap: image.PixelMap) => {
  68. this.pixelMap = pixelMap;
  69. this.imgSource?.release(); // 释放ImageSource
  70. });
  71. }
  72. })
  73. }
  74. @Builder
  75. staticBlurBuilder() {
  76. Stack({ alignContent: Alignment.Bottom }) {
  77. Image(this.pixelMap)
  78. .width('100%')
  79. .height('100%')
  80. .objectFit(ImageFit.Fill)
  81. Button('close')
  82. .width('90%')
  83. .height(40)
  84. .margin({ bottom: this.bottomSafeHeight + 16 })
  85. .onClick(() => {
  86. this.isShowStaticBlur = false;
  87. this.pixelMap?.release(); // 释放PixelMap
  88. })
  89. }
  90. .width('100%')
  91. .height('100%')
  92. }
  93. build() {
  94. NavDestination() {
  95. Column() {
  96. Button('static blur')
  97. .width('90%')
  98. .height(40)
  99. .onClick(() => {
  100. this.isShowStaticBlur = true;
  101. // 设置静态模糊
  102. this.staticBlur();
  103. })
  104. .bindContentCover(this.isShowStaticBlur, this.staticBlurBuilder(), {
  105. modalTransition: ModalTransition.DEFAULT
  106. })
  107. }
  108. .padding({ bottom: this.bottomSafeHeight + 16 })
  109. .width('100%')
  110. .height('100%')
  111. .justifyContent(FlexAlign.End)
  112. }
  113. .hideTitleBar(true)
  114. }
  115. }

缩小模糊半径

在对非图片组件(如Text组件)或不适用静态模糊的场景(如Gif动图)使用模糊时,若检测结果显示动态模糊绘制时出现丢帧异常,可以考虑缩小模糊半径,以优化图片模糊性能。

例如,从检测报告中可能故障原因中,点击组件所在源码文件,可跳转定位至ReduceBlurRadius.ets页面中的Text组件处。在示例代码中,使用了backdropBlur()对Text组件进行背景模糊,其模糊半径为2。

反例

收起
自动换行
深色代码主题
复制
  1. Text('Backdrop Blur')
  2. .padding(5)
  3. .width('90%')
  4. .height('50%')
  5. .fontSize(20)
  6. .fontColor(Color.White)
  7. .textAlign(TextAlign.Center)
  8. .backdropBlur(2)
  9. .backgroundImage($r('app.media.test'))
  10. .backgroundImageSize({ width: '90%' })
  11. .backgroundImagePosition(Alignment.Center)

优化建议

非图片模糊场景,建议缩小模糊半径。动态模糊每帧需重新计算,通过缩小半径,可降低性能消耗。

正例

收起
自动换行
深色代码主题
复制
  1. Text('Backdrop Blur')
  2. .padding(5)
  3. .width('90%')
  4. .height('50%')
  5. .fontSize(20)
  6. .fontColor(Color.White)
  7. .textAlign(TextAlign.Center)
  8. .backdropBlur(0.2) // 模糊半径减小至0.2,具体数值需根据实际需求而定
  9. .backgroundImage($r('app.media.test')) // 这里的 'app.media.test' 只是一个示例,开发者应将其替换为自己的内容
  10. .backgroundImageSize({ width: '90%' })
  11. .backgroundImagePosition(Alignment.Center)

表 1 常见的模糊API及其对应的优化建议

展开
模糊API和模糊类型 优化建议

blur:内容模糊

backdropBlur:背景模糊

backgroundBlurStyle:背景模糊

foregroundBlurStyle:内容模糊

backgroundEffect:背景模糊

1、若是图片组件,建议使用静态模糊;

2、若是非图片组件或不适用静态模糊的场景,建议减小模糊半径;

示例代码