HarmonyOS Repeat 可复用的循环渲染
HarmonyOS Repeat 可复用的循环渲染
什么是 Repeat
类似懒加载 LazyForEach,都能提高长列表的渲染性能,都能实现组件的动态渲染和释放,节省内存。区别主要是:
-
Repeat 直接监听状态变量的变化,而 LazyForEach 需要开发者实现IDataSource接口
Repeat 使用起来要更加简单一些
-
Repeat 还增强了节点复用能力,提高了长列表滑动和数据更新的渲染性能。
Repeat 存在缓冲池,需要复用节点的时候可以从缓冲池中获取,LazyForEach 是直接重新创建
-
Repeat 增加了渲染模板(template)的能力,在同一个数组中,根据开发者自定义的模板类型(template type)渲染不同的子组件。
适用于不同结构的组件可以提前把结构定义在模板 template 中,简化 UI 结构
Repeat 也可以看成是 LazyForEach 的升级版。
核心概念
关键字 | 说明 |
---|---|
each | 渲染普通节点 |
templateId | 指定要使用的模板的 id |
template | 模板 |
key | 要循环渲染的节点的唯一标志 |
virtualScroll | 打开懒加载,totalCount 为期望加载的数据长度 |
onMove | 列表项拖拽事件 |
cachedCount | 设置预加载数量和是否开启动画-默认开启 |
组件复用的基本原理
Repeat 根据当前的有效加载范围(屏幕可视区域+预加载区域)按需创建子组件
组件复用的过程
首次渲染时
- L1 缓存为 Repeat 有效加载区域
- L2 缓存为每个循环渲染模板的空闲节点缓存池。
开始滑动列表
将屏幕向右滑动(屏幕内容右移)一个节点的距离,Repeat 将开始复用缓存池中的节点。index=10 的节点进入有效加载范围,计算
出其 template type 为 bb。由于 bb 缓存池非空,Repeat 会从 bb 缓存池中取出一个空闲节点进行复用,更新其节点属性,该子组件中涉
及数据 item 和索引 index 的其他孙子组件会根据 V2 状态管理的规则做同步更新。其他节点仍在有效加载范围,均只更新索引 index。
index=0 的节点滑出了有效加载范围。当 UI 主线程空闲时,会检查 aa 缓存池是否已满,此时 aa 缓存池未满,将该节点加入到对应的缓
存池中。
如果此时对应 template type 的缓存池已满,Repeat 会销毁掉多余的节点。
数据更新
删除 index=4 的节点,修改节点数据 item_7 为 new_7。
首先,删除 index=4 的节点后,失效节点加入 aa 缓存池。后面的列表节点前移,新进入有效加载区域的节点 item_11 会复用 bb 缓存池
中的空闲节点,其他节点均只更新索引 index。
最后,节点 item_5 前移,索引 index 更新为 4。根据 template type 的计算规则,节点 item_5 的 template type 变为 aa,需要从 aa 缓存池中复用空闲节点,并且将旧节点加入 bb 缓存池
基本使用
对于结构固定的组件,可以使用 Repeat 和 each 的简单搭配
// 在List容器组件中使用Repeat
@Entry
@ComponentV2
// 推荐使用V2装饰器
struct RepeatExample {
@Local dataArr: Array<string> = []; // 数据源
aboutToAppear(): void {
for (let i = 0; i < 50; i++) {
this.dataArr.push(`data_${i}`); // 模拟动态加载数据
}
}
build() {
Column() {
List() {
Repeat<string>(this.dataArr)
.each((ri: RepeatItem<string>) => {
ListItem() {
Text('each_' + ri.item).fontSize(30)
}
})
.virtualScroll({ totalCount: this.dataArr.length }) // 打开懒加载,totalCount为期望加载的数据长度
}
.cachedCount(2) // 容器组件的预加载区域大小
.height('70%')
.border({ width: 1 }) // 边框
}
}
}
效果
搭配 template 使用
-
templateId 指定模板 id
-
template 声明模板
// 在List容器组件中使用Repeat
@Entry
@ComponentV2
// 推荐使用V2装饰器
struct RepeatExampleWithTemplates {
@Local dataArr: Array<string> = []; // 数据源
aboutToAppear(): void {
for (let i = 0; i < 50; i++) {
this.dataArr.push(`data_${i}`); // 为数组添加一些数据
}
}
build() {
Column() {
List() {
Repeat<string>(this.dataArr)
.each((ri: RepeatItem<string>) => { // 默认渲染模板
ListItem() {
Text('each_' + ri.item).fontSize(30).fontColor('rgb(161,10,33)') // 文本颜色为红色
}
})
.key((item: string, index: number): string => JSON.stringify(item)) // 键值生成函数
.virtualScroll({ totalCount: this.dataArr.length }) // 打开懒加载,totalCount为期望加载的数据长度
.templateId((item: string, index: number): string => { // 根据返回值寻找对应的模板子组件进行渲染
return index <= 4 ? 'A' : (index <= 10 ? 'B' : ''); // 前5个节点模板为A,接下来的5个为B,其余为默认模板
})
.template('A', (ri: RepeatItem<string>) => { // 'A'模板
ListItem() {
Text('A_' + ri.item).fontSize(30).fontColor('rgb(23,169,141)') // 文本颜色为绿色
}
}, { cachedCount: 3 }) // 'A'模板的缓存列表容量为3
.template('B', (ri: RepeatItem<string>) => { // 'B'模板
ListItem() {
Text('B_' + ri.item).fontSize(30).fontColor('rgb(39,135,217)') // 文本颜色为蓝色
}
}, { cachedCount: 4 }) // 'B'模板的缓存列表容量为4
}
.cachedCount(2) // 容器组件的预加载区域大小
.height('70%')
.border({ width: 1 }) // 边框
}
}
}
效果
更多使用场景
特别注意
节点更新说明
Repeat 子组件的节点操作分为四种:节点创建、节点更新、节点复用、节点销毁。其中,节点更新和节点复用的区别为:
- 节点更新:节点不销毁,状态变量驱动节点属性更新。
- 节点复用:旧节点不销毁,存储在空闲节点缓存池;需要创建新节点时,直接从缓存池中获取可复用的旧节点,并做相应的节点属性更新。
使用限制
使用限制
-
Repeat 必须在滚动类容器组件内使用,仅有List、Grid、Swiper以及WaterFlow组件支持 Repeat 懒加载场景。
循环渲染只允许创建一个子组件,子组件应当是允许包含在容器组件中的子组件。例如:Repeat 与List组件配合使用时,子组件必须为ListItem组件。
-
Repeat 不支持 V1 装饰器,混用 V1 装饰器会导致渲染异常。
-
滚动容器组件内只能包含一个 Repeat。以 List 为例,同时包含 ListItem、ForEach、LazyForEach 的场景是不推荐的;同时包含多个 Repeat 也是不推荐的。
-
当 Repeat 与自定义组件或[@Builder](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-builder)函数混用时,必须将 RepeatItem 类型整体进行传参,组件才能监听到数据变化。详见Repeat 与@Builder 混用。
关于我们
如果你兴趣想要了解更多的鸿蒙应用开发细节和最新资讯,甚至你想要做出一款属于自己的应用!欢迎在评论区留言或者私信或者看我个人信息,可以加入技术交流群。
- 0回答
- 6粉丝
- 1关注
- Repeat:子组件复用
- 鸿蒙HarmonyOS ArkTS循环渲染控制详解
- HarmonyOS NEXT《ArkTS渲染控制完全指南:条件与循环渲染深度解析》
- 鸿蒙-状态管理V1和V2在ForEach循环渲染的表现
- 鸿蒙开发:组件样式的复用
- HarmonyOS 组件复用 @Reusable 装饰器的基本使用
- HarmonyOS 组件复用 @ReusableV2 装饰器的基本使用
- 如何实现跨文件组件复用
- 鸿蒙特效教程06-可拖拽网格
- 【HarmonyOS NEXT】Tabs组件实现类微信(可滑动的)tabBar页签切换页面功能
- 41. [HarmonyOS NEXT Row案例九] 打造流畅可滑动列表项:滑动操作按钮的高级实现
- [HarmonyOS NEXT 实战案例:分割布局] 进阶篇 - 设置中心的动态内容与复用构建
- OpenHarmony 关于页面渲染的性能优化方案
- HarmonyOS性能优化——渲染范围控制
- HarmonyNext 中的高性能图形渲染技术详解