Harmony之路:列表的艺术——List与ForEach高效渲染
一、引入:为什么需要列表组件?
在移动应用开发中,列表是最常见的UI组件之一,无论是商品列表、消息列表还是设置项列表,都离不开高效的列表渲染。HarmonyOS提供了强大的List组件和ForEach循环渲染机制,能够帮助我们快速构建流畅的列表界面。掌握列表渲染技术,是构建复杂应用的基础能力。
二、讲解:List组件与ForEach循环渲染
1. List组件基础用法
List是HarmonyOS中用于展示可滚动列表的容器组件,支持垂直和水平两种滚动方向,能够自动处理超出屏幕内容的滚动显示。
基础列表示例:
@Entry
@Component
struct BasicList {
@State items: string[] = ['苹果', '香蕉', '橙子', '葡萄', '西瓜']
build() {
List({ space: 20 }) { // 设置列表项间距
ForEach(this.items, (item: string) => {
ListItem() {
Text(item)
.fontSize(20)
.fontColor(Color.Black)
}
.padding(10)
.backgroundColor(Color.White)
.borderRadius(8)
}, (item: string) => item) // 使用数据项作为key
}
.width('100%')
.height('100%')
.backgroundColor('#F5F5F5')
}
}
关键属性说明:
- space:设置列表项之间的间距,支持数字或百分比
- listDirection:设置列表滚动方向(Axis.Vertical垂直,Axis.Horizontal水平)
- alignListItem:设置列表项在交叉轴的对齐方式
2. ForEach循环渲染机制
ForEach是ArkUI框架提供的循环渲染组件,能够根据数组数据动态生成UI组件。它通过键值生成器(keyGenerator)来唯一标识每个列表项,实现高效的组件复用。
ForEach核心参数:
ForEach(
arr: Array<any>, // 数据源数组
itemGenerator: (item: any, index?: number) => void, // 组件生成函数
keyGenerator?: (item: any, index?: number) => string // 键值生成函数
)
键值生成的重要性:
- 唯一性:每个列表项必须有唯一的key,用于标识组件身份
- 稳定性:key在数据排序变化时不应改变,避免组件重建
- 性能优化:正确的key策略能够显著提升列表性能
3. 复杂数据列表渲染
实际开发中,我们通常使用对象数组作为数据源,每个对象包含多个属性。
商品列表示例:
// 定义数据模型
class Product {
id: string;
name: string;
price: number;
image: Resource;
constructor(id: string, name: string, price: number, image: Resource) {
this.id = id;
this.name = name;
this.price = price;
this.image = image;
}
}
@Entry
@Component
struct ProductList {
@State products: Product[] = [
new Product('1', '华为Mate60', 6999, $r('app.media.mate60')),
new Product('2', 'MateBook Pro X', 13999, $r('app.media.matebook')),
new Product('3', 'Watch GT4', 1438, $r('app.media.watch'))
]
build() {
List({ space: 15 }) {
ForEach(this.products, (product: Product) => {
ListItem() {
Row({ space: 12 }) {
Image(product.image)
.width(80)
.height(80)
.objectFit(ImageFit.Cover)
.borderRadius(8)
Column({ space: 5 }) {
Text(product.name)
.fontSize(18)
.fontWeight(FontWeight.Bold)
Text(`¥${product.price}`)
.fontSize(16)
.fontColor('#FF3A30')
}
.layoutWeight(1)
Button('购买')
.width(60)
.height(30)
.fontSize(12)
.onClick(() => {
console.log(`购买商品: ${product.name}`)
})
}
.padding(15)
}
}, (product: Product) => product.id) // 使用唯一ID作为key
}
.width('100%')
.height('100%')
.backgroundColor('#F8F9FA')
}
}
4. 列表分组展示
对于需要分组展示的数据,可以使用ListItemGroup组件实现分组效果。
分组列表示例:
class Group {
title: string;
items: Product[];
constructor(title: string, items: Product[]) {
this.title = title;
this.items = items;
}
}
@Entry
@Component
struct GroupList {
@State groups: Group[] = [
new Group('手机', [
new Product('1', '华为Mate60', 6999, $r('app.media.mate60')),
new Product('2', '小米14', 4999, $r('app.media.xiaomi'))
]),
new Group('笔记本', [
new Product('3', 'MateBook Pro X', 13999, $r('app.media.matebook')),
new Product('4', 'MacBook Pro', 12999, $r('app.media.macbook'))
])
]
build() {
List({ space: 10 }) {
ForEach(this.groups, (group: Group) => {
ListItemGroup({ header: this.buildGroupHeader(group.title) }) {
ForEach(group.items, (product: Product) => {
ListItem() {
Row({ space: 10 }) {
Image(product.image)
.width(60)
.height(60)
Text(product.name)
.fontSize(16)
Text(`¥${product.price}`)
.fontSize(14)
.fontColor('#FF3A30')
}
.padding(10)
}
}, (product: Product) => product.id)
}
}, (group: Group) => group.title)
}
.width('100%')
.height('100%')
}
@Builder
buildGroupHeader(title: string) {
Text(title)
.fontSize(18)
.fontWeight(FontWeight.Bold)
.fontColor(Color.Black)
.backgroundColor('#F0F0F0')
.padding({ left: 15, top: 10, bottom: 10 })
.width('100%')
}
}
5. 列表性能优化
对于长列表场景,性能优化至关重要。HarmonyOS提供了多种优化手段:
懒加载优化:
// 使用LazyForEach替代ForEach进行懒加载
List() {
LazyForEach(this.dataSource, (item: Product) => {
ListItem() {
// 列表项内容
}
}, (item: Product) => item.id)
}
.cachedCount(5) // 设置预加载数量
组件复用优化:
@Reusable
@Component
struct ProductItem {
@Prop product: Product;
build() {
// 列表项组件
}
}
布局优化建议:
- 减少嵌套层级,避免过度绘制
- 为组件设置固定宽高,减少重绘计算
- 使用扁平化布局,减少节点数量
6. 列表交互功能
列表通常需要支持点击、长按等交互操作。
交互功能示例:
@Entry
@Component
struct InteractiveList {
@State items: string[] = ['选项1', '选项2', '选项3', '选项4']
@State selectedIndex: number = -1;
build() {
List({ space: 0 }) {
ForEach(this.items, (item: string, index: number) => {
ListItem() {
Row({ space: 10 }) {
Text(item)
.fontSize(16)
.fontColor(this.selectedIndex === index ? Color.Blue : Color.Black)
if (this.selectedIndex === index) {
Image($r('app.media.check'))
.width(20)
.height(20)
}
}
.padding(15)
.width('100%')
}
.onClick(() => {
this.selectedIndex = index;
})
.onLongPress(() => {
console.log(`长按了: ${item}`);
})
}, (item: string) => item)
}
.width('100%')
.height('100%')
.divider({ strokeWidth: 0.5, color: Color.Gray })
}
}
三、总结:列表开发的核心要点
✅ 核心知识点回顾
- List组件是基础:掌握List的基本属性和布局方式,理解垂直和水平滚动的区别
- ForEach循环渲染:学会使用ForEach遍历数据数组,理解key生成器的重要性
- 数据模型设计:合理设计数据对象,为列表项提供完整的数据结构
- 分组展示:使用ListItemGroup实现分组列表,提升用户体验
- 性能优化:针对长列表场景,采用懒加载、组件复用等优化手段
- 交互功能:实现列表项的点击、长按等交互操作
⚠️ 常见问题与解决方案
- 列表项不更新:检查key生成器是否唯一且稳定,避免使用数组索引作为key
- 性能卡顿:对于长列表,使用LazyForEach和组件复用优化
- 布局错乱:为列表项设置固定宽高,避免使用百分比导致的重绘计算
- 内存泄漏:在列表项组件中合理管理资源,避免不必要的内存占用
🎯 最佳实践建议
- 数据驱动:采用MVVM模式,将数据与UI分离,提高代码可维护性
- 组件化思维:将复杂列表项封装为独立组件,提高代码复用率
- 性能监控:使用DevEco Studio的性能分析工具,监控列表渲染性能
- 多设备适配:在不同设备上测试列表布局,确保良好的响应式效果
下一步预告:在第七篇中,我们将深入学习组件间通信,掌握@Prop、@Link、@Provide等装饰器的使用,实现父子组件间的数据传递与状态同步。

浙公网安备 33010602011771号