当前位置: 首页 > news >正文

鸿蒙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)    }  }}

效果如下:

图片

http://www.lryc.cn/news/481739.html

相关文章:

  • 鸿蒙基本组件结构
  • 柔性鞋材振动刀智能视觉裁切机市场报告:未来几年年复合增长率CAGR为5.4%
  • 【计算机网络】基础知识,常识应用知识
  • 【Linux进程篇1】认识冯·诺依曼体系结构(引出进程详解)
  • 使用iviewui组件库的坑
  • 高级sql使用技巧
  • 403 Request Entity Too Lager(请求体太大啦)
  • Flutter 正在切换成 Monorepo 和支持 workspaces
  • 小白初入Android_studio所遇到的坑以及怎么解决
  • NetCore使用Aop和内存缓存对接口、方法进行数据缓存
  • playwright学习记录2--定位方式
  • 响应式网页设计--html
  • C#核心(8) 静态成员
  • 关于git使用的图文教程(包括基本使用,处理冲突问题等等)超详细
  • Axios 的 responseType 属性详解及 Blob 与 ArrayBuffer 解析
  • redis集群介绍
  • JDK中常用的包有哪些?
  • 校园官网练习---web
  • MySQL中指定字段的某个值排在前面
  • 【51单片机】I2C总线详解 + AT24C02
  • 直接插入排序法
  • mysql中InnoDB索引与MyISAM索引
  • Redis如何保证数据不丢失(可靠性)
  • 【计网】物理层学习笔记
  • vue链接跳转
  • IP地址是电脑自带的吗?是根据什么而决定的‌
  • JavaFX史上最全教程 - Shape - JavaFX矩形椭圆
  • SpringBoot实现的企业资产管理系统
  • python-读写Excel:openpyxl-(4)下拉选项设置
  • 【C++】详解RAII思想与智能指针