鸿蒙UI开发——自定义UI绘制帧率

1、概 述

随着设备屏幕的不断演进,当前主流设备采用LTPO屏幕(可变刷新率屏幕),此类屏幕支持在多个档位之间切换屏幕帧率。

对于快速变化的内容,如射击游戏,交互动画等,显示帧率越高,画面越流畅,但是相对的功耗也会越高。

而低速变化的内容,如游戏大厅,时钟更新动画等,画面更新频率较低,使用相对低的显示帧率,用户也不会觉得卡顿,但是相对的功耗就比较低。

基于显示内容的可变帧率能力,在具备LTPO屏幕的设备上,可以达到性能体验和功耗间的平衡。

HarmonyOS支持可变帧率能力,我们通过使用可变帧率接口,进行相关业务开发,可以享受可变帧率特性带来的功耗收益。

可变帧率为应用开发中的动画组件、XComponent组件、UI绘制等提供一种基础帧率配置和能力。

通过设置有效的期望绘制帧率后,系统会收集设置的请求帧率,进行决策和分发,在渲染管线上进行分频,尽量能够满足调用方的期望帧率。

【在我们自己希望独立绘制渲染一些内容时(例如使用Canvas自定义一些动态效果),也可以考虑用这种方式】

2、配置自定义UI绘制帧率

如果我们需要以独立的帧率绘制更新操作UI界面时,可以通过DisplaySync来实现。

模块如下:

复制代码
import { displaySync } from '@kit.ArkGraphics2D';

创建一个DisplaySync对象方法如下:

复制代码
let backDisplaySync: displaySync.DisplaySync = displaySync.create();

DisplaySync对象定义如下:

复制代码
class DisplaySync {  // 设置期望的帧率范围。  setExpectedFrameRateRange(rateRange: ExpectedFrameRateRange) : void  // 订阅每一帧变化  on(type: 'frame', callback: Callback<IntervalInfo>): void  // 取消订阅每一帧的变化  off(type: 'frame', callback?: Callback<IntervalInfo>): void  // 开始每帧回调  start(): void  // 停止每帧回调  stop(): void}// 设置帧率范围的入参结构如下class ExpectedFrameRateRange {  min: number,  // 期望的最小帧率。  max: number,  // 期望的最大帧率。  expected: number, // 期望的最优帧率。}

此处以不同帧率改变文件组件字体大小为例,来模拟不同UI绘制帧率的效果。步骤如下:

**👉🏻 step 1:导入模块并定义DisplaySync对象。**​​​​​​

复制代码
import { displaySync } from '@kit.ArkGraphics2D';@Entry@Componentstruct Index {  // 定义两个DisplaySync变量(slow是30帧,fast是60帧),未初始化  private backDisplaySyncSlow: displaySync.DisplaySync | undefined = undefined;  private backDisplaySyncFast: displaySync.DisplaySync | undefined = undefined;}

**👉🏻 step 2:定义两个文本组件。**​​​​​​​

复制代码
@State drawFirstSize: number = 25;@State drawSecondSize: number = 25;@Builder doSomeRenderFirst() { Text('30')   .fontSize(this.drawFirstSize)}@Builder doSomeRenderSecond() { Text('60')   .fontSize(this.drawSecondSize)}

**👉🏻 step 3:**通过DisplaySync实例设置帧率和注册订阅函数。****​​​​​​​

复制代码
CreateDisplaySyncSlow() {    let range : ExpectedFrameRateRange = { // 创建和配置帧率参数      expected: 30, // 设置期望绘制帧率为30hz      min: 0, // 配置帧率范围      max: 120 // 配置帧率范围    };    let draw30 = (intervalInfo: displaySync.IntervalInfo) => { // 订阅回调函数,字体大小在25到150之间变化      if (this.isBigger_30) {        this.drawFirstSize += 1;        if (this.drawFirstSize > 150) {          this.isBigger_30 = false;        }      } else {        this.drawFirstSize -= 1;        if (this.drawFirstSize < 25) {          this.isBigger_30 = true;        }      }    };
    this.backDisplaySyncSlow = displaySync.create(); // 创建DisplaySync实例    this.backDisplaySyncSlow.setExpectedFrameRateRange(range); // 设置帧率    this.backDisplaySyncSlow.on("frame", draw30); // 订阅frame事件和注册订阅函数}

**👉🏻 step 4:**开始每帧回调****​​​​​​​

复制代码
Button('Start')  .id('CustomDrawStart')  .fontSize(14)  .fontWeight(500)  .margin({ bottom: 10, left: 5 })  .fontColor(Color.White)  .onClick((): void => {      if (this.backDisplaySyncSlow == undefined) {        this.CreateDisplaySyncSlow();      }      if (this.backDisplaySyncFast == undefined) {        this.CreateDisplaySyncFast();      }      if (this.backDisplaySyncSlow) {        this.backDisplaySyncSlow.start();      }      if (this.backDisplaySyncFast) {        this.backDisplaySyncFast.start();      }    })    .width('20%')    .height(40)    .shadow(ShadowStyle.OUTER_DEFAULT_LG)

👉🏻 step 5:结束每帧回调****​​​​​​​

复制代码
Button('Stop')  .id('CustomDrawStop')  .fontSize(14)  .fontWeight(500)  .margin({ bottom: 10, left: 5 })  .fontColor(Color.White)  .onClick((): void => {    if (this.backDisplaySyncSlow) {        this.backDisplaySyncSlow.stop();    }    if (this.backDisplaySyncFast) {        this.backDisplaySyncFast.stop();    }  })  .width('20%')  .height(40)  .shadow(ShadowStyle.OUTER_DEFAULT_LG)

3、一个完整实例​​​​​​​

复制代码
import { displaySync } from '@kit.ArkGraphics2D';@Entry@Componentstruct Index {  @State drawFirstSize: number = 25;  @State drawSecondSize: number = 25;  private backDisplaySyncSlow: displaySync.DisplaySync | undefined = undefined;  private backDisplaySyncFast: displaySync.DisplaySync | undefined = undefined;  private isBigger_30:boolean = true;  private isBigger_60:boolean = true;  @Builder doSomeRenderFirst() {    Text('30')      .fontSize(this.drawFirstSize)  }  @Builder doSomeRenderSecond() {    Text('60')      .fontSize(this.drawSecondSize)  }  CreateDisplaySyncSlow() {    // 定义期望绘制帧率    let range : ExpectedFrameRateRange = {      expected: 30,      min: 0,      max: 120    };    let draw30 = (intervalInfo: displaySync.IntervalInfo) => {      if (this.isBigger_30) {        this.drawFirstSize += 1;        if (this.drawFirstSize > 150) {          this.isBigger_30 = false;        }      } else {        this.drawFirstSize -= 1;        if (this.drawFirstSize < 25) {          this.isBigger_30 = true;        }      }    };    this.backDisplaySyncSlow = displaySync.create(); // 创建DisplaySync实例    this.backDisplaySyncSlow.setExpectedFrameRateRange(range); // 设置帧率    this.backDisplaySyncSlow.on("frame", draw30); // 订阅frame事件和注册订阅函数  }  CreateDisplaySyncFast() {    // 定义期望绘制帧率    let range : ExpectedFrameRateRange = {      expected: 60,      min: 0,      max: 120    };    let draw60 = (intervalInfo: displaySync.IntervalInfo) => {      if (this.isBigger_60) {        this.drawSecondSize += 1;        if (this.drawSecondSize > 150) {          this.isBigger_60 = false;        }      } else {        this.drawSecondSize -= 1;        if (this.drawSecondSize < 25) {          this.isBigger_60 = true;        }      }    };    this.backDisplaySyncFast= displaySync.create(); // 创建DisplaySync实例    this.backDisplaySyncFast.setExpectedFrameRateRange(range); // 设置帧率    this.backDisplaySyncFast.on("frame", draw60); // 订阅frame事件和注册订阅函数  }  aboutToDisappear() {    if (this.backDisplaySyncSlow) {      this.backDisplaySyncSlow.stop(); // DisplaySync失能关闭      this.backDisplaySyncSlow = undefined; // 实例置空    }    if (this.backDisplaySyncFast) {      this.backDisplaySyncFast.stop(); // DisplaySync失能关闭      this.backDisplaySyncFast = undefined; // 实例置空    }  }  build() {    Column() {      Row() {        this.doSomeRenderFirst();      }      .height('40%')      Row() {        this.doSomeRenderSecond();      }      .height('40%')      Row() {        Button('Start')          .id('CustomDrawStart')          .fontSize(14)          .fontWeight(500)          .margin({ bottom: 10, left: 5 })          .fontColor(Color.White)          .onClick((): void => {            if (this.backDisplaySyncSlow == undefined) {              this.CreateDisplaySyncSlow();            }            if (this.backDisplaySyncFast == undefined) {              this.CreateDisplaySyncFast();            }            if (this.backDisplaySyncSlow) {              this.backDisplaySyncSlow.start(); // DisplaySync使能开启            }            if (this.backDisplaySyncFast) {              this.backDisplaySyncFast.start(); // DisplaySync使能开启            }          })          .width('20%')          .height(40)          .shadow(ShadowStyle.OUTER_DEFAULT_LG)        Button('Stop')          .id('CustomDrawStop')          .fontSize(14)          .fontWeight(500)          .margin({ bottom: 10, left: 5 })          .fontColor(Color.White)          .onClick((): void => {            if (this.backDisplaySyncSlow) {              this.backDisplaySyncSlow.stop(); // DisplaySync失能关闭            }            if (this.backDisplaySyncFast) {              this.backDisplaySyncFast.stop(); // DisplaySync失能关闭            }          })          .width('20%')          .height(40)          .shadow(ShadowStyle.OUTER_DEFAULT_LG)      }      .width('100%')      .justifyContent(FlexAlign.Center)      .shadow(ShadowStyle.OUTER_DEFAULT_SM)      .alignItems(VerticalAlign.Bottom)      .layoutWeight(1)    }  }}

效果如下:

相关推荐
遇到困难睡大觉哈哈2 小时前
HarmonyOS —— Remote Communication Kit 拦截器(Interceptor)高阶定制能力笔记
笔记·华为·harmonyos
遇到困难睡大觉哈哈4 小时前
HarmonyOS —— Remote Communication Kit 定制处理行为(ProcessingConfiguration)速记笔记
笔记·华为·harmonyos
氤氲息4 小时前
鸿蒙 ArkTs 的WebView如何与JS交互
javascript·交互·harmonyos
遇到困难睡大觉哈哈4 小时前
HarmonyOS支付接入证书准备与生成指南
华为·harmonyos
赵浩生4 小时前
鸿蒙技术干货10:鸿蒙图形渲染基础,Canvas绘图与自定义组件实战
harmonyos
赵浩生4 小时前
鸿蒙技术干货9:deviceInfo 设备信息获取与位置提醒 APP 整合
harmonyos
BlackWolfSky4 小时前
鸿蒙暂未归类知识记录
华为·harmonyos
lin62534225 小时前
Android右滑解锁UI,带背景流动渐变动画效果
android·ui