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

HarmonyOS4.0——ArkUI应用说明

一、ArkUI框架简介

ArkUI开发框架是方舟开发框架的简称,它是一套构建 HarmonyOS / OpenHarmony 应用界面的声明式UI开发框架,它使用极简的UI信息语法、丰富的UI组件以及实时界面语言工具,帮助开发者提升应用界面开发效率 30%,开发者只需要使用一套 TS / JS API,就能在多个 HarmonyOS / OpenHarmony 设备上提供既丰富又流畅的用户界面体验。

1.1.UI开发框架

什么是UI开发框架?

  • UI:即用户界面,主要包含视觉(比如文字、图像、动画等可以看到的内容)以及交互(比如点击按钮、滑动列表、放缩图片等用户操作)。

  • UI框架:是为软件应用开发者提供开发UI的基础设施,主要包括UI控件(按钮/列表等)、视图布局(摆放/排列相应的UI控件)、动画机制(动画设计以及效果呈现)、交互事件处理(点击/滑动)等,以及相应的编程语言和编程模型等。

UI编程框架提供了开发以及运行UI界面所需要的框架能力,如下图所示:

说明:

  • 开发模型:对开发者提供开发范式、UI控件、布局、动效、交互、编程语言等。体现出来的是开发时候的难以程度和开发效率。
  • 运行框架:UI界面渲染及交互的基础能力框架,包括相应的布局引擎、控件机制、动画引擎、事件机制、渲染管线等,并结合语言虚拟机和图形引擎,将开发者的程序运行在具体系统平台上。体现出来的是应用运行的性能体验。
  • 平台适配:承载框架的具体操作系统或平台适配层。

1.2.ArkUI框架的演进

ArkUI开发框架综合考虑了UI渲染、语言和运行效率,围绕着极简开发、高性能、跨设备跨平台进一步演进。下图是ArkUI整体架构的演进:

上图中左侧是 2020 年 HarmonyOS 发布的JS UI框架的架构示意图,主要支持类Web的前端开发范式,通过DSL(domain-specific language,领域特定语言)转换层,跨语言对接到声明式UI后端引擎,并结合JS引擎完成整体UI渲染。右侧是ArkUI开发框架,主要有以下几个变化:

  1. 引入了新一代的声明式UI开发范式,实现极简的UI描述语法。
  2. 设计了统一的前后端扁平化渲染机制,进一步提升UI渲染的性能并降低内存消耗。
  3. 深度结合 ArkCompiler 方舟编译器和 ArkRuntime 方舟运行时,提升语言的执行性能和跨语言通信能力。
  4. 在工具方面,针对新一代的声明式UI开发范式构建了新的编译工具链和预览引擎,提供了所见即所得的实时预览机制。

另外,在ArkUI开发框架中,类Web范式会继续保留,即类Web范式和新一代的声明式UI范式都可以支持,可以各自独立使用,但不能混用。

1.3.ArkUI的关键特性

①.极简的UI信息语法

ArkUI开发框架采用基于 TypeScript 扩展的极简的声明式UI描述界面语法,提供了类自然语言的UI描述和组合,开发者只需用几行简单直观的声明式代码,即可完成界面功能。

②.丰富的内置UI组件

ArkUI开发框架内置了丰富而精美的多态组件,可满足大部分应用界面开发的需求,开发者可以轻松地向几乎任何UI控件添加动画并选择一系列框架内置的动画能力,可为用户带来平滑而自然的体验。其中多态是指UI描述是统一的,UI呈现在不同类型设备上会有所不同。比如 Button 组件在手机和手表会有不同的样式和交互方式。

③.多维度的状态管理机制

ArkUI开发框架为开发者提供了跨设备数据绑定功能和多维度的状态管理机制(组件内/组件间/全局/分布式数据驱动UI变更),支持灵活的数据驱动的UI变更,帮助开发者节省70%代码完成跨端界面应用开发。

④.支持多设备开发

ArkUI开发框架除了提供UI开发套件外还围绕着多设备开发提供了多维度的解决方案,进一步简化开发:

  • 基础开发能力:包括基础的分层参数配置(比如色彩、字号、圆角、间距等),栅格系统,原子化布局能力(比如拉伸、折行、隐藏等)。
  • 零部件组件层:包括多态控件,统一交互能力,以及在此基础上的组件组合。
  • 面向典型场景:提供分类的页面组合模板以及示例代码。

⑤.原生性能体验

ArkUI开发框架内置了许多核心的UI控件和动效,如图片、列表、网格、属性动画、转场动画等,加持自研的 ArkCompiler 方舟编译器和 ArkRuntime 方舟运行时深度优化,这些都可以在 HarmonyOS / OpenHarmony 设备上达到移动原生应用一样的性能体验。

⑥.实时预览机制

ArkUI开发框架支持实时界面预览特性可帮助开发快速的所见即所得的开发和调测界面,无需连接真机设备就可以显示应用界面在任何 HarmonyOS / OpenHarmony 设备上的UI效果,预览的关键特性主要包括:

  • 一致性渲染:和目标设备一致的UI呈现效果。
  • 实时性预览:改动相应的代码,实时呈现出相应UI效果。另外,代码能够和UI双向联动,代码改动的同时UI也实时变更,UI改动的同时代码也相应地变更。
  • 多维度预览:支持页面级预览、组件级预览、多设备预览。

1.4.声明式UI开发范式的基本组成

1.4.1.创建项目

创建项目说明

1.4.2.基本组成说明

下面我们以一个具体的示例来说明新一代声明式UI开发范式的基本组成。如下图所示的代码示例,UI界面会显示一个 数字 按钮。当用户点击 + 按钮时,每点击一次会加 1

上面的案例构成说明如下:

  • 装饰器:用来装饰类、结构体、方法以及变量,赋予其特殊的含义,上面 @Entry@Component@State 都是装饰器。
    • @Component 表示这是个自定义组件;
    • @Entry 则表示这是个页面入口组件,也就是根组件;
    • @State 表示组件中的状态变量,这个状态变化会引起UI变更。
  • 自定义组件:可复用的UI单元,可组合其它组件,如上述被 @Component 装饰的 struct Index 。
  • UI描述:声明式的方式来描述UI的结构,如上述 build() 方法内部的代码块。
  • 内置组件:框架中默认内置的基础组件,可直接被开发者调用,比如上面案例的Button
  • 事件方法:用于添加组件对事件的响应逻辑,统一通过事件方法进行设置,如跟随在Button后面的onClick()方法。
  • 属性方法:用于组件属性的配置,统一通过属性方法进行设置,如fontSize()width()height()size()等,可通过链式调用的方式设置多项属性。

上述示例中,用 @State 装饰的变量 times ,包含了一个基础的状态管理机制,即 times 的值的变化,会引起相应的UI组件Button的变化,ArkUI开发框架还提供多维度的状态管理机制,和UI相关联的数据,不仅仅在组件内使用,还可以在不同组件层级间传递,比如父子组件之间,爷孙组件之间,也可以是全局范围内的传递,还可以是跨设备传递。

二、资源管理

应用开发过程中,经常需要用到颜色、字体、间距、图片等资源,在不同的设备或配置中,这些资源的值可能不同。

  • 应用资源:借助资源文件能力,开发者在应用中自定义资源,自行管理这些资源在不同的设备或配置中的表现。

  • 系统资源:开发者直接使用系统预置的资源定义(即分层参数,同一资源ID在设备类型、深浅色等不同配置下有不同的取值)。

2.1.资源分类

移动端应用开发常用到的资源比如图片、音视频和字符串等在OpenHarmony 规定把这些应用的资源文件统一放在 resources 目录下的各子目录中便于开发者使用和维护, resoures 目录包括两大类,

  • 一类为 base 目录与限定词目录
  • 另一类为 rawfile 目录

新建 OpenHarmony 应用,默认生成的资源目录如下所示:

base 目录与限定词目录下面可以创建资源组目录(包括 elementmediaprofile ),用于存放特定类型的资源文件,各资源目录说明如下图所示:

2.2.资源访问

OpenHarmony 应用资源分为两类,一类是应用资源,另一类是系统资源,它们的资源访问方式如下:

1)访问应用资源

base 目录下的资源文件会被编译成二进制文件并且给这些资源赋予唯一的 ID ,使用相应资源的时候通过资源访问符 $r(‘app.type.name’) 的形式,

  • app 代表是应用内 resources 目录中定义的资源;
  • type 表示资源类型,可取值的有有 color 、 float 、 string 、 string 、 media 等;
  • name 表示资源的文件名字。

例如:string.json 中新加 name 为 text_string 的字符串,则访问该字符串资源为 $r(‘app.string.text_string’):

base 目录的子目录element下新建 float.json ,string.json 、color.json文件,分别存放浮点型、字体和颜色,资源内容如下图所示:

需要注意的是因为国际化的问题:

  • string.json中配置的内容需要在,在zh_CN和en_US的string.json中添加相同的内容,就会根据本地的语言环境进行显示:

在media准备一张图片,后面作为文本框的背景图使用:

创建:ResourceDemo.ets文件,应用上面的内容如下:

@Entry
@Component
struct ResourceDemo{build(){Column(){Text($r('app.string.hi_string')) //访问字符串资源.size({width:300, height:120}) //设置尺寸.fontSize($r('app.float.text_size'))//访问字体大小.fontColor($r('app.color.text_color'))//访问字体颜色.backgroundImage($r('app.media.Sns'), ImageRepeat.XY) //设置背景图片,ImageRepeat.XY则是图片太小时候,选择某个坐标位置的颜色填充}.width("100%") //表示将组件的宽度设置为父容器的100%.height("100%") //表示将组件的高度设置为父容器的100%.padding(10)//表示设置组件的内边距为10个单位。}
}

预览效果如下:

2)访问系统资源

除了自定义资源,开发者也可以使用系统中预定义的资源,统一应用的视觉风格。可以查看应用UX设计中关于资源的介绍,获取支持的系统资源ID及其在不同配置下的取值。在开发过程中,分层参数的用法与资源限定词基本一致。对于系统资源,可以通过“$r(‘sys.type.resource_id’)”的形式引用。其中,sys为系统资源;type为资源类型,取值包括“color”、“float”、“string”、“media”;resource_id为资源id。说明

  • 仅声明式开发范式支持使用系统资源。
  • 对于系统预置应用,建议使用系统资源;对于三方应用,可以根据需要选择使用系统资源或自定义应用资源。

案例,创建 ResourceDemo2.ets内容如下:

@Entry
@Component
struct ResourceDemo2{build(){Column(){Text('HelloWorld').fontColor($r('sys.color.ohos_id_color_emphasize'))            // 设置字体颜色.fontSize($r('sys.float.ohos_id_text_size_headline5'))         // 设置字体大小.fontFamily($r('sys.string.ohos_id_text_font_family_medium'))  // 设置字体.backgroundColor($r('sys.color.ohos_id_color_palette_aux1'))   // 设置背景颜色Image($r('sys.media.ohos_app_icon')).border({color: $r('sys.color.ohos_id_color_palette_aux11'),           // 设置边框颜色为辅助色11radius: $r('sys.float.ohos_id_corner_radius_button'),         // 设置边框圆角半径为按钮圆角半径width: 2                                                      // 设置边框宽度为2}).margin({top: $r('sys.float.ohos_id_elements_margin_horizontal_m'),    // 设置上边距为水平中等间距bottom: $r('sys.float.ohos_id_elements_margin_horizontal_l')  // 设置下边距为水平大间距}).height(200)                                                    // 设置高度为200.width(300)                                                     // 设置宽度为300}.width("100%").height("100%").padding(10)}
}

预览结果如下:

2.3.像素单位

1)像素单位说明
ArkUI开发框架提供了 4 种像素单位供开发者使用,分别是: px 、 vp 、 fp 和 lpx ,框架采用vp为基准数据单位。它们之间的区别如下表所示:

2)像素单位转换
提供其他单位与px单位互相转换的方法。

案例如下:

@Entry
@Component
struct Example {build() {Column() {/**Flex({ wrap: FlexWrap.Wrap })是一个Flex布局的设置,*其中wrap: FlexWrap.Wrap表示设置Flex容器的子元素在主轴方向上超出容器时是否换行。*在这里,FlexWrap.Wrap表示子元素会自动换行,以适应容器的尺寸。* 这样设置可以确保在容器尺寸不足以容纳所有子元素时,子元素会自动换行,而不会超出容器范围。*/Flex({ wrap: FlexWrap.Wrap }) {// 默认不写单位就是是vpColumn() {Text("width(220)").width(220)  // 设置宽度为220vp.height(40)  // 设置高度为40vp.backgroundColor("#00BFC9")  // 设置背景颜色为#00BFC9.fontSize("12vp")  // 设置字体大小为12vp}.margin(5)  // 设置外边距为5vp// 宽度指定成pxColumn() {Text("width('220px')").width('220px')  // 设置宽度为220px.height(40)  // 设置高度为40vp.backgroundColor("#007900")  // 设置背景颜色为#007900.textAlign(TextAlign.Center)  // 设置文本对齐方式为居中.fontColor(Color.White)  // 设置字体颜色为白色}.margin(5)  // 设置外边距为5vp// 宽度指定成vpColumn() {Text("width('220vp')").width('220vp')  // 设置宽度为220vp.height(40)  // 设置高度为40vp.backgroundColor("#FF9800")  // 设置背景颜色为#FF9800.textAlign(TextAlign.Center)  // 设置文本对齐方式为居中.fontColor(Color.White)  // 设置字体颜色为白色.fontSize('12vp')  // 设置字体大小为12vp}.margin(5)  // 设置外边距为5vp// 宽度指定成vplpxColumn() {Text("width('220lpx') designWidth:720").width("220lpx")  // 设置宽度为220lpx.height(40)  // 设置高度为40vp.backgroundColor("#634794")  // 设置背景颜色为#634794.textAlign(TextAlign.Center)  // 设置文本对齐方式为居中.fontColor(Color.White)  // 设置字体颜色为白色.fontSize('12vp')  // 设置字体大小为12vp}.margin(5)  // 设置外边距为5vp// 将vp单位的数值转换为以px为单位的数值Column() {Text("width(vp2px(220) + 'px')").width(vp2px(220) + 'px')  // 将220vp转换为px单位的数值,然后设置宽度.height(40)  // 设置高度为40vp.backgroundColor('#3F56EA')  // 设置背景颜色为#3F56EA.textAlign(TextAlign.Center)  // 设置文本对齐方式为居中.fontColor(Color.White)  // 设置字体颜色为白色.fontSize('12vp')  // 设置字体大小为12vp}.margin(5)  // 设置外边距为5vp// fontSize('12fp')设置成fpColumn() {Text("fontSize('12fp')").width(220)  // 设置宽度为220vp.height(40)  // 设置高度为40vp.backgroundColor('#A14A5C')  // 设置背景颜色为#A14A5C.textAlign(TextAlign.Center)  // 设置文本对齐方式为居中.fontColor(Color.White)  // 设置字体颜色为白色.fontSize('12fp')  // 设置字体大小为12fp}.margin(5)  // 设置外边距为5vp// 将px单位的数值转换为以vp为单位的数值。Column() {Text("width(px2vp(220))").width(px2vp(220))  // 将220px转换为vp单位的数值,然后设置宽度.height(40)  // 设置高度为40vp.backgroundColor('#E40078')  // 设置背景颜色为#E40078.textAlign(TextAlign.Center)  // 设置文本对齐方式为居中.fontColor(Color.White)  // 设置字体颜色为白色.fontSize('12fp')  // 设置字体大小为12fp}.margin(5)  // 设置外边距为5vp}.width('100%')  // 设置宽度为100%}}
}

2.4.资源管理器

ArkUI开发框架在 @ohos.resourceManager 模块里提供了资源管理器 ResourceManager,它可以访问不同的资源,比如获取获取字符串资源,获取设备配置信息等等,参考地址:https://developer.harmonyos.com/cn/docs/documentation/doc-references-V3/js-apis-resource-manager-0000001478181625-V3,resourceManager 模块 API 如下:

declare namespace resourceManager {// 省略部分代码export interface ResourceManager {// 获取字符串资源getString(resId: number, callback: AsyncCallback<string>): void;// 获取字符串数组资源getStringArray(resId: number, callback: AsyncCallback<Array<string>>): void;// 获取媒体资源getMedia(resId: number, callback: AsyncCallback<Uint8Array>): void;// 获取设备信息,比如当前屏幕密度,设备类型是手机还是平板等getDeviceCapability(callback: AsyncCallback<DeviceCapability>): void;// 获取配置信息,比如当前屏幕方向密度,当前设备语言getConfiguration(callback: AsyncCallback<Configuration>): void;// 释放ResourceManager资源release();}
}
export default resourceManager;

使用 ResourceManager 之前先调用 getContext(this) 方法获取当前组件的 Context,该 Conetxt 内部定义了一个 ResourceManager 的属性,因此可以直接使用 ResourceManager 的各种 getXXX() 方法获取对应资源, ResourceManager应用流程如下:

1)引入 resourceManager

import resourceManager from '@ohos.resourceManager';

2)获取 ResourceManager

aboutToAppear() {// 获取ResourceManagerlet manager = getContext(this).resourceManager;
}

3)使用 ResourceManager

manager.getString(0x1000001, (innerError, data) => {if(data) {// 获取资源成功} else {console.log("error: " + JSON.stringify(innerError))}
})

4)释放 ResourceManager

this.manager.release();

完整案例如下:

import resourceManager from '@ohos.resourceManager';  // 导入资源管理器模块@Entry
@Component
struct Example02{@State text_string: string = "";  // 定义文本字符串状态@State capability: string = "";  // 定义设备能力状态@State configuration: string = "";  // 定义设备配置状态private resManager: resourceManager.ResourceManager;  // 声明资源管理器build(){Column({space:10}){  // 创建一个垂直布局的Column组件,设置子元素间距为10Text(this.text_string)  // 显示文本字符串资源.size({width:300, height:120})  // 设置尺寸为宽300,高120.fontSize($r('app.float.text_size'))  // 使用资源管理器获取字体大小.fontColor($r('app.color.text_color'))  // 使用资源管理器获取字体颜色.backgroundImage($r('app.media.Sns'))  // 使用资源管理器设置背景图片Text(this.capability)  // 显示设备能力信息.fontSize(20)  // 设置字体大小为20Text(this.configuration)  // 显示设备配置信息.fontSize(20)  // 设置字体大小为20}.width('100%')  // 设置宽度为100%.height('100%')  // 设置高度为100%.padding(10)  // 设置内边距为10}aboutToAppear(){this.resManager = getContext(this).resourceManager;  // 获取上下文中的资源管理器this.resManager.getStringValue(0x1000001,(innerError,data)=>{  // 获取字符串资源值if(data){this.text_string = data;  // 将获取到的字符串资源值赋给text_string状态}else{console.log("error:"+JSON.stringify(innerError));  // 打印错误信息}this.resManager.getDeviceCapability((innerError, deviceCapability)=>{  // 获取设备能力信息if(deviceCapability){this.capability = JSON.stringify(deviceCapability);  // 将设备能力信息转换为JSON字符串并赋给capability状态}})this.resManager.getConfiguration((innerError, configuration)=>{  // 获取设备配置信息if(configuration){this.configuration = JSON.stringify(configuration);  // 将设备配置信息转换为JSON字符串并赋给configuration状态}})})}aboutToDisappear(){this.resManager?.release();  // 释放资源管理器资源}
}

注意:渲染出来的 mock string 是因为在预览器上暂时不支持 ResourceManager 的用法,在实际设备上可以执行。

三、渲染控制语法

ArkTS也提供了渲染控制的能力。条件渲染可根据应用的不同状态,渲染对应状态下的UI内容。循环渲染可从数据源中迭代获取数据,并在每次迭代过程中创建相应的组件。参考网址:

https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ets-rendering-control-0000001149698611

3.1.if/else条件渲染

使用 if/else 进行条件渲染需要注意以下情况:

  • if 条件语句可以使用状态变量。
  • 使用 if 可以使子组件的渲染依赖条件语句。
  • 必须在容器组件内使用。
  • 某些容器组件限制子组件的类型或数量。将if放置在这些组件内时,这些限制将应用于 if 和 else 语句内创建的组件。例如,Grid 组件的子组件仅支持 GridItem 组件,在 Grid 组件内使用条件渲染时,则 if 条件语句内仅允许使用 GridItem 组件。

案例如下:

@Entry
@Component
struct ComponentTest {@State showImage: boolean = false;  // 定义showImage状态,默认为falsebuild() {// 纵向布局元素垂直方向间距。Column({space:10}){  // 创建一个垂直布局的Column组件,设置子元素间距为10// 如果showImage为true,则显示图片,否则显示"Loading ....."if(this.showImage){Image($r('app.media.Sns'))  // 显示图片,使用资源管理器获取图片资源.width(160)  // 设置宽度为160.height(60)  // 设置高度为60.backgroundColor(Color.Pink)  // 设置背景颜色为粉色}else {Text("Loading .....").fontSize(23)  // 设置字体大小为23.fontColor('#FFFFF0') //设置字体颜色为象牙色.width(160)  // 设置宽度为160.height(60)  // 设置高度为60.backgroundColor(Color.Pink)  // 设置背景颜色为粉色.textAlign(TextAlign.Center)  // 设置文本居中对齐}Button(this.showImage?'Image Loaded':'Load Image')  // 按钮内容根据showImage状态动态显示.size({width:160,height:40})  // 设置按钮的宽和高.backgroundColor(this.showImage?'#3F56EA':'#9C554B')  // 根据showImage状态设置按钮背景色.onClick(()=>{  // 点击事件处理this.showImage = true;  // 点击后设置showImage值为true,显示图片})}.width('100%')  // 设置宽度为100%.height('100%')  // 设置高度为100%.padding(10)  // 设置内边距为10}
}

预览效果如下:

3.2.ForEach循环渲染

ArkUI开发框架提供循环渲染(ForEach组件)来迭代数组,并为每个数组项创建相应的组件。ForEach 定义如下:

3.2.ForEach循环渲染

ArkUI开发框架提供循环渲染(ForEach组件)来迭代数组,并为每个数组项创建相应的组件。ForEach 定义如下:

interface ForEach {(arr: Array<any>, itemGenerator: (item: any, index?: number) => void,keyGenerator?: (item: any, index?: number) => string): ForEach;
}

说明:

  • arr:必须是数组,允许空数组,空数组场景下不会创建子组件。
  • itemGenerator:子组件生成函数,为给定数组项生成一个或多个子组件。
  • keyGenerator:匿名参数,用于给定数组项生成唯一且稳定的键值。

案例如下:

@Entry
@Component
struct ComponentTest02 {//准备源数据private textArray:string[] = ["一","二","三","四","五"]  // 定义一个包含字符串的数组作为源数据build() {Column({space:10}){  // 创建一个垂直布局的Column组件,设置子元素间距为10ForEach(this.textArray,(item:string,index?:number)=>{  // 遍历textArray数组Text(`标题:${item}`)  // 显示带有标题前缀的文本.fontSize(20)  // 设置字体大小为20.backgroundColor('#00B377')  // 设置背景颜色为绿色.margin({top:10})  // 设置上边距为10.fontColor('#FFFFF0')  // 设置字体颜色为白色})}.width("100%")  // 设置宽度为100%.height("100%")  // 设置高度为100%.padding(10)  // 设置内边距为10}
}

预览后效果如下:

3.3.数据懒加载LazyForEach循环渲染

ArkUI开发框架通过数据懒加载(LazyForEach)从提供的数据源中按需迭代数据,并在每次迭代过程中创建相应的组件。

1)LazyForEach 定义如下:

// LazyForEach定义
interface LazyForEach {(dataSource: IDataSource, itemGenerator: (item: any, index?: number) => void,keyGenerator?: (item: any, index?: number) => string): LazyForEach;
}// IDataSource定义
export declare interface IDataSource {totalCount(): number;getData(index: number): any;registerDataChangeListener(listener: DataChangeListener): void;unregisterDataChangeListener(listener: DataChangeListener): void;
}// DataChangeListener定义
export declare interface DataChangeListener {onDataReloaded(): void;onDataAdded(index: number): void;onDataMoved(from: number, to: number): void;onDataDeleted(index:number): void;onDataChanged(index:number): void;
}

说明如下:

  • itemGenerator:子组件生成函数,为给定数组项生成一个或多个子组件。
  • keyGenerator:匿名参数,用于给定数组项生成唯一且稳定的键值。
  • dataSource:实现 IDataSource 接口的对象,需要开发者实现相关接口。

2)IDataSource 定义如下:

export declare interface IDataSource {totalCount(): number;getData(index: number): any;registerDataChangeListener(listener: DataChangeListener): void;unregisterDataChangeListener(listener: DataChangeListener): void;
}

说明如下:

  • totalCount:获取数据总数。
  • getData:获取索引对应的数据。
  • registerDataChangeListener:注册改变数据的监听器。
  • unregisterDataChangeListener:注销改变数据的监听器。

3)DataChangeListener 定义如下:

export declare interface DataChangeListener {onDataReloaded(): void;onDataAdded(index: number): void;onDataMoved(from: number, to: number): void;onDataDeleted(index:number): void;onDataChanged(index:number): void;
}

说明如下:

  • onDataReloaded:item重新加载数据时的回调。
  • onDataAdded:item新添加数据时的回调。
  • onDataMoved:item数据移动时的回调。
  • onDataDeleted:item数据删除时的回调。
  • onDataChanged:item数据变化时的回调。

案例如下:

//##########################构造数据################################
//定义student
class Student{public sid: number; // 学生IDpublic name: string; // 学生姓名public age: number; // 学生年龄public address: string; // 学生地址public avatar: string; // 学生头像//构造方法constructor(sid: number, name: string, age: number, address: string, avatar: string) {this.sid = sid; // 初始化学生IDthis.name = name; // 初始化学生姓名this.age = age; // 初始化学生年龄this.address = address; // 初始化学生地址this.avatar = avatar; // 初始化学生头像}
}// 定义一个抽象类 BaseDataSource,使用泛型 T,实现接口 IDataSource
abstract class BaseDataSource<T> implements IDataSource {private dataSource: T[] = new Array(); // 数据源,使用泛型数组// 构造方法,接收一个泛型数组作为参数,用于初始化数据源constructor(dataList: T[]) {this.dataSource = dataList; // 初始化数据源}// 返回数据源的长度totalCount(): number {return this.dataSource == null ? 0 : this.dataSource.length;}// 获取指定索引的数据,如果索引合法则返回数据,否则返回 nullgetData(index: number): T | null {return index >= 0 && index < this.totalCount() ? this.dataSource[index] : null;}// 注册数据变化监听器,这里的方法体为空,需要在子类中实现具体逻辑registerDataChangeListener(listener: DataChangeListener) {}// 取消注册数据监听器,这里的方法体为空,需要在子类中实现具体逻辑unregisterDataChangeListener() {}
}// 继承 BaseDataSource 类,指定泛型为 Student 类型
class StudentDataSource extends BaseDataSource<Student> {constructor(students: Student[]) {super(students); // 调用父类构造函数进行初始化}
}//产生数据
function mock():Student[]{let students = [];for (let i = 1; i < 21; i++) {//模拟学生数据students[i] = new Student(i,"student:"+i, i+10, "address:"+i, "app.media.Sns");}return students;
}@Entry
@Component
struct ComponentTest03 {// mock数据private student: Student[] = mock(); // 模拟学生数据// 创建dataSourceprivate dataSource: StudentDataSource = new StudentDataSource(this.student); // 创建学生数据源build() {Column({ space: 10 }) { // 创建一个垂直布局的列,设置间距为10List() { // 创建一个列表LazyForEach(this.dataSource, (item: Student) => { // 使用自定义dataSource进行懒加载ListItem() { // 创建列表项Row() { // 创建一个水平布局的行Image($r("app.media.Sns")) // 显示学生头像.height('100%') // 设置高度为100%.width(80) // 设置宽度为80Column() { // 创建一个垂直布局的列Text(this.getName(item)) // 调用getName方法验证懒加载.fontSize(20) // 设置字体大小为20Text('address: ' + item.address) // 显示学生地址.fontSize(17) // 设置字体大小为17}.margin({ left: 5 }) // 设置左边距为5.alignItems(HorizontalAlign.Start) // 设置子元素水平方向对齐方式为起始位置.layoutWeight(1) // 设置布局权重为1}.width('100%') // 设置宽度为100%.height('100%') // 设置高度为100%}.width('100%') // 设置宽度为100%.height(60) // 设置高度为60})}.divider({ // 设置列表的分隔线样式strokeWidth: 3, // 分隔线宽度为3color: Color.Gray // 分隔线颜色为灰色}).width('90%') // 设置宽度为90%.height(160) // 设置高度为160.backgroundColor(Color.Pink) // 设置背景颜色为粉色}.width('100%') // 设置宽度为100%.height('100%') // 设置高度为100%.padding(10) // 设置内边距为10}getName(item: Student): string {console.log("index: " + item.sid); // 打印学生索引日志return 'index:' + item.sid + ", " + item.name; // 返回学生索引和姓名}
}

执行后效果如下:

输出的日志如下:

说明:

  • LazyForEach必须在容器组件内使用,目前仅有List、Grid以及Swiper组件支持数据懒加载(即只加载可视部分以及其前后少量数据用于缓冲,避免过多的占用资源),其他组件仍然是一次性加载所有的数据。
  • LazyForEach在每次迭代中,必须创建且只允许创建一个子组件。
  • 生成的子组件必须是允许包含在LazyForEach父容器组件中的子组件。
  • 允许LazyForEach包含在if/else条件渲染语句中,但不* 允许LazyForEach中出现if/else条件渲染语句。
  • 为了高性能渲染,通过DataChangeListener对象的onDataChange方法来更新UI时,仅当itemGenerator中创建的子组件内使用了状态变量时,才会触发组件刷新。
  • itemGenerator函数的调用顺序不一定和数据源中的数据项相同,在开发过程中不要假设itemGenerator和keyGenerator函数是否执行及其执行顺序。例如,以下示例可能无法正常工作:
LazyForEach(dataSource, item => Text(`${item.i}. item.data.label`)),item => item.data.id.toString())

为了能让大家更好的学习鸿蒙 (OpenHarmony) 开发技术,这边特意整理了《鸿蒙 (OpenHarmony)开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05

《鸿蒙 (OpenHarmony)开发学习手册》

入门必看:https://qr21.cn/FV7h05

  1. 应用开发导读(ArkTS)
  2. ……

HarmonyOS 概念:https://qr21.cn/FV7h05

  1. 系统定义
  2. 技术架构
  3. 技术特性
  4. 系统安全

如何快速入门?:https://qr21.cn/FV7h05

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. 构建第一个JS应用
  4. ……

开发基础知识:https://qr21.cn/FV7h05

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ……

基于ArkTS 开发:https://qr21.cn/FV7h05

1.Ability开发
2.UI开发
3.公共事件与通知
4.窗口管理
5.媒体
6.安全
7.网络与链接
8.电话服务
9.数据管理
10.后台任务(Background Task)管理
11.设备管理
12.设备使用信息统计
13.DFX
14.国际化开发
15.折叠屏系列
16.……

相关文章:

HarmonyOS4.0——ArkUI应用说明

一、ArkUI框架简介 ArkUI开发框架是方舟开发框架的简称&#xff0c;它是一套构建 HarmonyOS / OpenHarmony 应用界面的声明式UI开发框架&#xff0c;它使用极简的UI信息语法、丰富的UI组件以及实时界面语言工具&#xff0c;帮助开发者提升应用界面开发效率 30%&#xff0c;开发…...

基于模块自定义扩展字段的后端逻辑实现(二)

目录 一&#xff1a;创建表 二&#xff1a;代码逻辑 上一节我们详细讲解了自定义扩展字段的逻辑实现和表的设计&#xff0c;这一节我们以一个具体例子演示下&#xff0c;如何实现一个订单模块的自定义扩展数据。 一&#xff1a;创建表 订单主表: CREATE TABLE t_order ( …...

图像中部分RGB矩阵可视化

图像中部分RGB可视化 今天室友有个需求就是模仿下面这张图画个示意图&#xff1a; 大致就是把图像中的一小部分区域的RGB值可视化了一下。他居然不知道该怎么画&#xff0c;我寻思这不直接秒了。 import cv2 as cv import numpy as np import matplotlib.pyplot as pltclass …...

RPA财务机器人在厦门市海沧医院财务管理流程优化汇总的应用

目前国内外研究人员对于RPA机器人在财务管理流程优化领域中的应用研究层出不穷&#xff0c;但现有研究成果主要集中在财务业务单一领域&#xff0c;缺乏财务管理整体流程一体化管控的研究。RPA机器人的功能绝非单一的财务业务处理&#xff0c;无论从自身技术发展&#xff0c;或…...

聚焦老年生活与健康,“老有所依·情暖夕阳”元岗街社区微型养老博览会顺利开展

尊老敬老是中华民族的传统美德&#xff0c; 爱老助老是全社会的共同责任。 家有一老&#xff0c;如有一宝&#xff0c; 长者的生活情况是一个家庭的头等大事&#xff0c; 做好长者服务是街道和社区的重要工作。 2024年1月6日&#xff0c;由元岗街道党工委、元岗街道办事处、…...

记录汇川:H5U与Factory IO测试12

主程序&#xff1a; 子程序&#xff1a; IO映射 子程序&#xff1a; 辅助出料 子程序&#xff1a; 自动程序 Factory IO配置&#xff1a; 实际动作如下&#xff1a; Factory IO测试12...

PingCAP 受邀参加 FICC 2023,获 Open100 世纪全球开源贡献奖

2023 年 12 月&#xff0c;2023 国际测试委员会智能计算与芯片联邦大会&#xff08;FICC 2023&#xff09;在海南三亚举办&#xff0c;中外院士和数十位领域专家莅临出席。 大会现场 &#xff0c;开放源代码促进会创始人 Bruce Perens 颁发了 Open100 世纪全球开源贡献奖&…...

10-skywalking告警

https://github.com/apache/skywalking/blob/master/docs/en/setup/backend/backend-alarm.md 5.1&#xff1a;告警指标 ~$ vim /apps/apache-skywalking-apm-bin/config/oal/core.oal service_resp_time # 服务的响应时间 service_sla # 服务http请求成功率SLV&#xff0c;比…...

vue前端开发自学,插槽练习第二次,name属性的使用

vue前端开发自学,插槽练习第二次,name属性的使用!可以使用name属性&#xff0c;来自定义一个名字&#xff0c;这样&#xff0c;就可以在一个组件内同时出现多个插槽的内容了。在子组件内接收的时候&#xff0c;很简答&#xff0c;只需要在slot标签里面加上name“mz”&#xff1…...

AI副业拆解:人像卡通化,赋予你的形象全新生命力

大家好我是在看&#xff0c;记录普通人学习探索AI之路。 &#x1f525;让你的形象瞬间穿越二次元&#xff01;&#x1f680;人像卡通化&#xff0c;捕捉你的独特魅力&#xff0c;让真实与梦幻在此刻交融。&#x1f3a8; 今天为大家介绍如何免费把人像卡通化--漫画风 https://w…...

宝塔面板安装MySQL8数据库

第一步&#xff1a;搜索mysql 第二步: 点击安装 我这里选择安装8版本 第三步&#xff1a;给宝塔配置mysql防火墙 第四步&#xff1a;修改数据库密码 第五步&#xff1a;想要使用navicat连接 需要修改root的权限 &#xff08;1&#xff09;使用secureCRT先登录mysql (2) 输入u…...

中科星图——Landsat9_C2_SR大气校正后的地表反射率数据

数据名称&#xff1a; Landsat9_C2_SR 数据来源&#xff1a; USGS 时空范围&#xff1a; 2022年1月-2023年3月 空间范围&#xff1a; 全国 数据简介&#xff1a; Landsat9_C2_SR数据集是经大气校正后的地表反射率数据&#xff0c;属于Collection2的二级数据产品&#…...

使用ros_arduino_bridge控制机器人底盘

使用ros_arduino_bridge控制机器人底盘 搭建了ROS分布式环境后,将ros_arduino_bridge功能包上传至Jetson nano&#xff0c;就可以在PC端通过键盘控制小车的运动了。实现流程如下&#xff1a; 系统准备&#xff1b;下载程序&#xff1b;程序修改&#xff1b;分别启动PC与Jetson…...

Nacos下载与安装【windows】

&#x1f95a;今日鸡汤&#x1f95a; 我不知将去何方&#xff0c;但我已经在路上。 ——宫崎骏《千与千寻》 目录 &#x1f95e;1.Nacosdi地址 &#x1f32d;2.GitHub下载 &#x1f37f;3.目录结构 &#x1f953;4.启动nacos &#x1f9c2;5.客户端登陆 &#x1f9c8…...

【随笔】遗传算法优化的BP神经网络(随笔,不是很详细)

文章目录 一、算法思想1.1 BP神经网络1.2 遗传算法1.3 遗传算法优化的BP神经网络 二、代码解读2.1 数据预处理2.2 GABP2.3 部分函数说明 一、算法思想 1.1 BP神经网络 BP神经网络&#xff08;Backpropagation Neural Network&#xff0c;反向传播神经网络&#xff09;是一种监…...

Mysql 嵌套子查询

文章目录 子查询 大家好&#xff01;我是夏小花&#xff0c;今天是2024年1月13日|腊月初三 子查询 需求是&#xff1a;最外层的查询语句里面包含四个不相同表的查询&#xff0c;根据月份进行关联查询&#xff0c;每个查询语句中的where条件可以自行去定义,最后返回数量和月份 …...

Qt QLabel标签控件

文章目录 1 属性和方法1.1 文本1.2 对齐方式1.3 换行1.4 图像 2. 实例2.1 布局2.2 为标签添加背景色2.3 为标签添加图片2.4 代码实现 QLabeI是Qt中的标签类&#xff0c;通常用于显示提示性的文本&#xff0c;也可以显示图像 1 属性和方法 QLabel有很多属性&#xff0c;完整的可…...

iOS14 Widget 小组件调研

桌面小组件是iOS14推出的一种新的桌面内容展现形式。 根据苹果的统计数据&#xff0c;“一般用户每天进入主屏幕的次数超过90次”&#xff0c;如果有一个我们应用的小组件在桌面&#xff0c;每天都有超过90次曝光在用户眼前的机会&#xff0c;这绝对是一个顶级的流量入口。 “…...

HarmonyOS的应用类型(FA vs Stage)

HarmonyOS目前提供两种应用模型 FA(Feature Ability)模型: HarmonyOS API 7开始支持的模型,已经不再主推。 Stage模型: HarmonyOS API 9开始新增的模型,是目前主推且会长期演进的模型。在该模型中,由于提供了AbilityStage、WindowStage等类作为应用组件和Window窗口的…...

Jeecg创建表单页面步骤

1.在Online表单开发里面新建一个表单页面&#xff0c;可以修改数据库属性、页面属性、校验字段、外键、索引&#xff0c;新建完成之后然后同步数据库 2.选中该表&#xff0c;然后生成代码&#xff0c;可以先把代码放在桌面&#xff0c;然后将文件夹是包名称的文件复制到后端代…...

leetcode17 电话号码的字母组合

方法1 if-else方法 if-else方法的思路及其简单粗暴&#xff0c;如下图所示&#xff0c;以数字234为例&#xff0c;数字2所对应的字母是abc&#xff0c;数字3所对应的是def&#xff0c;数字4所对应的是ghi&#xff0c;最后所产生的结果就类似于我们中学所学过的树状图一样&…...

用html和css实现一个加载页面【究极简单】

要创建一个简单的加载页面&#xff0c;你可以使用 HTML 和 CSS 来设计。以下是一个基本的加载页面示例&#xff1a; HTML 文件 (index.html): <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"…...

Android-消息机制Handler

Handler的机制:Android 消息传递机制就是handler。在多线程的应用场景中&#xff0c;将工作线程中需更新UI的操作信息 传递到 UI主线程&#xff0c;从而实现对UI的更新处理&#xff0c;最终实现异步消息的处理。多个线程并发更新UI的同时 保证线程安全。Handler只是一个入口&am…...

MySQL夯实之路-事务详解

事务四大特性 事务需要通过严格的acid测试。Acid表示原子性&#xff0c;一致性&#xff0c;隔离性&#xff0c;持久性。 原子性&#xff08;atomicity&#xff09; 事务是不可分割的最小单元&#xff0c;对于整个事务的操作&#xff0c;要么全部提交成功&#xff0c;要么全部…...

安泰电子前置微小信号放大器怎么用的

前置微小信号放大器是一种重要的电子设备&#xff0c;用于放大微弱的输入信号&#xff0c;提高系统的灵敏度。它在各种领域中都有广泛的应用&#xff0c;包括音频、通信、测量等。在这篇文章中&#xff0c;我们将详细介绍前置微小信号放大器的使用方法&#xff0c;以便更好地理…...

【深度学习每日小知识】Overfitting 过拟合

过拟合是机器学习&#xff08;ML&#xff09;中的常见问题&#xff0c;是指模型过于复杂&#xff0c;泛化能力较差的场景。当模型在有限数量的数据上进行训练&#xff0c;并且学习了特定于该特定数据集的模式&#xff0c;而不是适用于新的、看不见的数据的一般模式时&#xff0…...

嵌入式必备的WEB知识

写在前面 嵌入式要学习Wed前端吗&#xff1f;答案是要的&#xff0c;不需要深入学习&#xff0c;只需要简单了解即可。为什么要学习&#xff1f; 原因如下&#xff1a; 可以远程控制和管理设备&#xff1a;通过简单的Web知识&#xff0c;嵌入式系统可以建立Web界面&#xff0c…...

Scipy 中级教程——信号处理

Python Scipy 中级教程&#xff1a;信号处理 Scipy 的信号处理模块提供了丰富的工具&#xff0c;用于处理和分析信号数据。在本篇博客中&#xff0c;我们将深入介绍 Scipy 中的信号处理功能&#xff0c;并通过实例演示如何应用这些工具。 1. 信号生成与可视化 首先&#xff…...

【排序篇2】选择排序、计数排序

目录 一、选择排序二、计数排序 一、选择排序 整体思想&#xff1a; 从数组中选出最小值和最大值放在起始位置&#xff0c;直到排序完成 具体步骤&#xff1a; 定义两个变量begin和end为下标&#xff0c;指向数组始末定义要找的最大值的下标为maxi&#xff0c;最小值的下标为…...

重生奇迹mu敏弓加点攻略

1. 选择正确的属性点分配 在重生奇迹mu游戏中敏弓的属性点分配非常重要。建议将主要属性点分配在敏捷和力量上这样可以提高敏弓的攻击力和闪避能力。适当加点在体力和魔力上可以提高敏弓的生存能力和技能释放次数。不要忘记适当加点在智力上可以提高敏弓的技能威力和命中率。 …...