【鸿蒙实战开发】HarmonyOS渲染控制

31 篇文章 0 订阅
31 篇文章 0 订阅

目录

  • 渲染控制概述
  • if/else:条件渲染
  • ForEac:循环渲染
  • LazyForEach:数据懒加载
  • Repeat:循环渲染(推荐)
  • ConnentSlot:混合开发

渲染控制概述

ArkUI通过自定义组件的build()函数和@builder装饰器声明式UI描述语句构建相应的的UI。在声明式描述语句中开发者除了使用系统组件外,还可以使用渲染语句来辅助UI的构建,这些渲染控制语句包括控制组件是否显示的条件语句,基于数组数据快速生成组件的虚幻渲染语句,针对大数据量的数据懒加载语句,针对混合模式开发的组件渲染语句。

if/else:条件渲染

ArkTS提供了渲染控制的能力,条件渲染可根据应用的不同状态,使用if、else和else if渲染对应状态下的UI内容。

使用规则

  • 支持if、else和else if语句
  • if、else后跟随的条件语句可以使用状态变量
  • 允许在容器组件内使用,通过条件渲染语句构建不同的子组件。
  • 条件渲染语句在涉及到组件的父子关系时是"透明"的,当父组件和子组件之间存在一个或多个if语句时,必须遵守父组件关于子组件使用的规则
  • 每个分支内部的构建海曙必须遵循构建函数的规则,并创建一个或多个组件。无法创建组建的空构建函数会产生语法错误
  • 某些容器组件限制子组件的类型或数量,将条件渲染语句用于这些组件内时,这些限制同样应用于条件渲染语句内创建的组件。例如:Grid容器组件的子组件仅支持GridItem组件,在Grid内使用条件渲染语句时,条件渲染语句内仅允许使用GridItem组件。

更新机制

当if、else后跟随的状态判断中使用的状态变量值变化时,条件渲染语句会进行更新,更新步骤如下:

  1. 评估if和else if的状态判断条件,如果分支没有变化,无需执行以下步骤。如果分支有变化,则执行2、3步骤
  2. 删除此前构建的所有子组件
  3. 执行新分支的构造函数,将获取到的组件添加到if父容器中。如果缺少适用的else分支,则不构建然和内容。 条件可以包括Typescript表达式。对于构造函数中的表达式,此类表达式不得更改应用程序状态。

ForEach:循环渲染

ForEach接口基于数组类型数据来进行需=循环渲染,需要与容器组件配合使用,且接口返回的数组应当是允许包含在ForEach父容器组件中的子组件。例如,ListItem组件要求ForEach的父容器组件必须为List组件

接口 描述

ForEach(
 arr: Array,
 itemGenerator: (item: Object, index: number) => void,
 keyGenerator?: (item: Object, index: number) => string
)

以下是参数的详细说明:

image.png

键值生成规则

在ForEach循环渲染过程中,系统会为每个数组元素生成一个唯一且持久的键值,用于表示对应的组件。当这个键值发生变化时,ArkUI框架将视为该数组元素已被替换或修改,并会基于新的键值创建一个新的组件。

ForEach提供了一个名为keyGenerator的参数,这是一个函数,开发者可以通过它自定义键值生成规则。如果开发者没有定义keyGenerator函数,则ArkUI框架会使用默认的键值生成函数。

ArkUI框架对于ForEach的键值生成有一套特定的判断规则,这主要与itemGenerator函数的第二个参数index以及keyGenerator函数的第二个参数index有关,具体的键值生成规则判断逻辑如下图:
image.png

LazyForEach:数据懒加载

LazyForEach从提供的数据源中按需迭代数据,并在每次迭代过程中创建相应的组件。当在滚动容器中使用了LazyForEach,框架会根据滚动容器可视区域按需创建组件,当组件划出可视区域外时,框架会进行组件销毁回收以降低内存占用。

接口描述


LazyForEach(
 dataSource:IDataSource, //需要进行数据迭代的数据源
 itemGenerator:(item:Object,index:number) => void, 
 keyGenerator:(item:Object,index:number) => string
):void

参数:

参数名参数类型必填参数描述
dataSourceIDataSourceLazyForEach数据源,需要开发者实现相关接口
itemGenerator(item:Objec,index:number) => void子组件生成函数,为数组中的每一个数据项创建一个子组件。
keyGenerator(item:Object,index:number) =>string简直生成函数,用于给数据源中的每一个数据项生成唯一且固定的键值。当数据项在数组中的位置更改时,其键值不得更改,当数组中的数据项被新项替换时,被替换的键值和新项的键值必须不同。键值生成器的功能是可选的,但是,为了使开发框架能更好的识别数组更改,提高性能,建议提供。如将数组反向时,如果没有提供键值生成器,则LazyForEach中的所有节点都将重建。

IDataSource类型说明

interface IDataSource {
 totalCount():number; //获得数据总数
 getData(index:number):Object; //获取索引值对应的数据
 registerDataChangeListener(listener:DataChangeListener):void; //注册数据改变的监听器
 unregisterDataChangeListener(listener:DataChangeListener):void; //注销数据改变的监听器
}

image.png

DataChangeListener类型说明

interface DataChangeListener {
 onDataReloaded():void; //重新加载数据完成调用
 onDataAdded(index:number):void; //添加数据完成后调用
 onDataMoved(from:number,to:number):void; //数据移动起始位置与数据移动目标位置交换完成后调用
 onDataDeleted(index:number):void; //删除数据完成后调用
 onDataChaged(index:number):void; //改变数据完成后调用
 onDataAdd(index:number):void; //添加数据完成后调用
 onDataMove(from:number,to:number):void; //数据移动起始位置与数据移动目标位置交换完成后调用
 onDataDelete(index:number):void; //删除数据完成后调用
 onDataChange(index:number):void; //改变数据完成后调用
 onDatasetChange(dataOperations:DataOperation[]):void; //批量数据处理后调用
}

DataOperation类型说明


type DataOperation = 
 DataAddOperation      |  //添加数据操作
 DataDeleteOperation   |  //删除数据操作
 DataChangeOperation   |  //改变数据操作
 DataMoveOperation     |  //移动数据操作
 DataExchangeOperation |  //交换数据操作
 DataReloadOperation      //重载所有数据操作

DataAddOperation

interface DataAddOperation {
 type:DataOperationType.ADD,    //数据添加类型
 index:number,                  //插入数据索引值
 count?:number,                 //插入数量,默认值为1
 ket?:string|Array<string>      //为插入的数据分配键值
}

DataDeleteOperation

interface DataDeleteOperation{
 type:DataOperationType.DELETE, //数据删除类型
 index:number,                  //起始删除位置索引值
 count?:number                  //删除数据数量,默认值为1
}

DataChangeOperation

interface DataChangeOperation{
 type:DataOperationType.CHANGE, //数据改变类型
 index:number,                  //改变的数据的索引值
 key?:string                    //为改变的数据分配新的键值,默认使用原键值
}

DataMoveOperation

interface MoveIndex {
 from:number;           //起始移动位置
 to:number;             //目的移动位置
}

interface DataMoveOperation {
 type:DataOperationType.MOVE, //数据移动类型
 index:MoveIndex,
 key?:string                  //为被移动的数据分配新的键值,默认使用原键值
}

DataExchangeOperation


interface ExchangeIndex {
 start:number;                     //第一个交换位置
 end:number;                       //第二个交换位置
}
interface ExchangeKey {
 start:string;                     //为第一个交换的位置分配新的键值,默认使用原键值
 end:string;                       //为第二个交换的位置分配新的键值,默认使用原键值
}
interface DataExchangeOperation {
 type:DataOperationType.EXCHANGE,  //数据交换类型
 index:ExchangeIndex,
 key?:ExchangeKey
}

DataReloadOperation


interface DataReloadOperation {      //当onDataChange含有DataOperationType.RELOAD操作时,其余操作全部失效,框架会自己调用keyGenerator进行键值比对
 type:DataOperationType.RELOAD    //数据全部重新加载
}

使用限制

  • LazyForEach必须在容器组件内使用,仅有List、Grid、Swiper以及WaterFlow组件支持数据懒加载(可配置cachedCount属性,即只加载可视部分以及其前后少量数据用于缓冲),其他组件仍然是一次性加载所有数据。
  • LazyForEach在每次迭代中,必须创建且只允许创建一个子组件
  • 生成的子组件必须是允许包含在LazyForEach父容器组件中的子组件
  • 允许LazyForEach包含在if/else条件渲染语句中,也允许LazyForEach中出现if/else条件渲染语句
  • 键值生成器必须针对每个数据生成唯一的值,如果键值相同,将导致键值相同的UI组件渲染出问题
  • LazyForEach必须使用DataChangeListener对象来进行更新,第一个参数dataSource使用状态变量时,状态变量改变不会触发LazyForEach的UI刷新
  • 为了高性能渲染,通过DataChangeListener对象的onDataChange方法来更新UI时,需要生成不同于原来的键值来触发组件刷新

键值生成规则

在LazyForEach循环渲染过程中,系统会为每个item生成一个唯一且持久的键值,用于标识对应的组件。当这个键值变化时,ArkUI框架将视为该数组元素已被替换或修改,并会基于新的键值创建一个新的组件。

LazyForEach提供了一个名为keyGenerator的参数,这是一个函数,开发者可以通过它自定义键值的生成规则。如果开发者没有定义keyGenerator函数,则ArkUI框架会使用默认的键值生成函数,即(item: Object, index: number) => { return viewId + ‘-’ + index.toString(); }, viewId在编译器转换过程中生成,同一个LazyForEach组件内其viewId是一致的。

Repeat:循环渲染(推荐)

Repeat组件基于数组类型数据进行循环渲染,需要与容器组件配合使用,且接口返回的数组应当是允许包含在Repeat父容器组件中的子组件。

Repeat循环渲染和ForEach相比有两个区别,一是优化了部分更新场景下的渲染性能,二是组件生成函数的索引index由框架侧来维护。

接口描述

Repeat 组件构造

declare const Repeat:<T>(arr:Array<T>) => RepeatAttribute<T>

参数说明:

参数名参数类型是否必填参数描述
arrArray<T>数据源,为Array<T>类型的数组,由开发者决定参数类型。

Repeat组件属性

declare class RepeatAttribute<T> {
 each(itemGenerator:(repeatItem:RepeatItem<T>) => void) : RepeatAttribute<T>;
 key(keyGenerator:(item:T,index:number) => string) : RepeatAttribute<T>;
}

参数说明:

image.png

RepeatItem 类型

interface RepeatItem<T> {
 item:T,
 index?:number
}

参数说明:

参数名参数类型是否必填参数描述
itemTarr中每一个数据项。T为开发者传入的数据类型
numbernumber当前数据项对应的索引

键值生成规则

在Repeat循环渲染过程中,系统会为每个数组元素生成一个唯一且持久的键值,用于标识对应的组件。当这个键值变化时,ArkUI框架将视为该数组元素已被替换或修改,会基于此去做对应的更新。若当前数组有数据项对应的键值与其他项重复,Repeat会为每一项数据补上index作为新的键值。

Repeat提供了key属性,参数是一个函数,开发者可以通过它自定义键值的生成规则。如果开发者没有调用key属性,则ArkUI框架会使用默认的键值生成函数。

ArkUI框架对于Repeat的键值生成有一套特定的判断规则,具体的键值生成规则判断逻辑如下图所示。

ContentSlot: 混合开发

用于渲染并管理Native层使用C-API创建的组件。
支持混合模式开发,当容器是ArkTS组件,子组件在Native侧创建时,推荐使用ContentSlot占位组件。

接口

ContentSlot组件接口


//当前开发者需要使用ArkUI提供的NodeContent作为管理器
ContentSlot(content:Content)
参数名类型必须参数描述
contentContentContent作为ContentSlot的管理器,通过Native侧提供的接口,可以注册并触发ContentSlot的上下树事件回调以及管理ContentSlot的子组件
abstract class Content {
}

ContentSlotInterface

(content:Content):ContentSlotAttribute;
当内容添加到占位符组件时调用

系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:

参数名类型必须参数描述
contentContentContent作为ContentSlot的管理器,通过Native侧提供的接口,可以注册并触发ContentSlot的上下树事件回调以及管理ContentSlot的子组件

ContentSlotAttribute

定义ContentSlot属性,以防止不正确的递归使用ContentSlot
系统能力: SystemCapability.ArkUI.ArkUI.Full

Native侧接口

接口名描述
OH_ArkUI_NodeContent_RegisterCallback(ArkUI_NodeContentHandle content, ArkUI_NodeContentCallback callback)向管理器Content上注册事件。
OH_ArkUI_NodeContentEvent_GetEventType(ArkUI_NodeContentEvent* event)获取Content上触发的事件类型。
OH_ArkUI_NodeContent_AddNode(ArkUI_NodeContentHandle content, ArkUI_NodeHandle node)在Content上添加子组件。
OH_ArkUI_NodeContent_InsertNode(ArkUI_NodeContentHandle content, ArkUI_NodeHandle node, int32_t position)在Content上插入子组件。
OH_ArkUI_NodeContent_RemoveNode(ArkUI_NodeContentHandle content, ArkUI_NodeHandle node)在Content上移除子组件。
OH_ArkUI_GetNodeContentFromNapiValue(napi_env env, napi_value value, ArkUI_NodeContentHandle* content)在Native侧获取ArkTS侧Content指针。
typedef enum {NOTE_CONTENT_EVENT_ON_ATTACH_TO_WINDOW = 0,NOTE_CONTENT_EVENT_ON_DETACH_FROM_WINDOW = 1,} ArkUI_NodeContentEventTypeContent上会触发的上树和下树两种事件类型。

写在最后

●如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
●点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
●关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
●更多鸿蒙最新技术知识点,请移步前往小编:https://gitee.com/

在这里插入图片描述

  • 12
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值