鸿蒙学习实战之路:List列表组件基础展示与数据绑定
List列表组件基础展示与数据绑定
引言
在HarmonyOS应用开发中,List组件是最常用且功能强大的数据展示控件之一。无论你是开发社交应用的消息列表、电商应用的商品列表,还是设置页面的选项列表,List组件都能提供流畅的滚动体验和高效的性能表现。本文将带你从零开始掌握List组件的使用,重点讲解基础展示、数据绑定以及实际开发中的最佳实践。
官方参考资料:
一、List组件基础概念
1.1 什么是List组件
List组件是一个可滚动的列表容器,用于呈现相同或相似类型的数据集合。它具有以下核心特性:
- 垂直滚动:默认支持垂直方向的滚动
- 高性能:采用懒加载机制,只渲染可视区域内的项
- 多样化布局:支持线性布局、网格布局等多种排列方式
- 丰富的交互:支持点击、长按、滑动等手势操作
1.2 List组件的基本结构
一个典型的List组件包含以下部分:
List() {
// 列表项内容
ListItem() {
// 列表项的具体UI组件
}
}
二、创建基础List列表
2.1 最简单的List示例
让我们从一个最基本的文本列表开始:
@Entry
@Component
struct BasicListExample {
build() {
Column() {
List({ space: 10 }) {
ListItem() {
Text('列表项1')
.fontSize(20)
.padding(10)
}
ListItem() {
Text('列表项2')
.fontSize(20)
.padding(10)
}
ListItem() {
Text('列表项3')
.fontSize(20)
.padding(10)
}
}
.width('100%')
.height('100%')
}
}
}
2.2 List核心属性详解
List组件提供了丰富的属性来控制列表的显示和行为:
| 属性名 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| space | number | 列表项之间的间距 | 0 |
| initialIndex | number | 初始滚动位置 | 0 |
| scroller | Scroller | 列表滚动控制器 | - |
| listDirection | Axis | 列表方向(垂直/水平) | Axis.Vertical |
重要提示:在实际开发中,建议始终设置List的宽度和高度,否则可能无法正常显示滚动效果。
三、数据绑定与动态列表
3.1 使用ForEach进行数据绑定
静态定义的列表在实际开发中很少使用,大多数情况下我们需要动态绑定数据:
@Entry
@Component
struct DynamicListExample {
// 定义数据源
private items: string[] = ['苹果', '香蕉', '橙子', '葡萄', '西瓜', '芒果']
build() {
Column() {
List({ space: 8 }) {
// 使用ForEach循环渲染列表项
ForEach(this.items, (item: string, index: number) => {
ListItem() {
Text(`${index + 1}. ${item}`)
.fontSize(18)
.fontColor(Color.Black)
.backgroundColor(Color.White)
.padding(12)
.width('100%')
}
}, (item: string) => item)
}
.width('100%')
.height('100%')
.divider({ strokeWidth: 1, color: '#F1F1F1' })
}
}
}
3.2 复杂数据结构的列表展示
实际应用中的数据通常更复杂,让我们看一个对象数组的示例:
// 定义数据模型
class Product {
id: number
name: string
price: number
category: string
constructor(id: number, name: string, price: number, category: string) {
this.id = id
this.name = name
this.price = price
this.category = category
}
}
@Entry
@Component
struct ProductListExample {
private products: Product[] = [
new Product(1, '华为Mate 60', 5999, '手机'),
new Product(2, '华为Watch 4', 2499, '智能手表'),
new Product(3, '华为MatePad', 3299, '平板电脑'),
new Product(4, '华为FreeBuds', 899, '耳机')
]
build() {
Column() {
List({ space: 12 }) {
ForEach(this.products, (product: Product) => {
ListItem() {
Column({ space: 8 }) {
Text(product.name)
.fontSize(20)
.fontColor('#0018A7')
.fontWeight(FontWeight.Bold)
.width('100%')
Row() {
Text(`¥${product.price}`)
.fontSize(16)
.fontColor('#E30000')
Text(product.category)
.fontSize(14)
.fontColor('#666666')
.margin({ left: 12 })
.backgroundColor('#F5F5F5')
.padding({ left: 8, right: 8, top: 2, bottom: 2 })
.borderRadius(4)
}
.width('100%')
.justifyContent(FlexAlign.Start)
}
.padding(16)
.backgroundColor(Color.White)
.borderRadius(8)
.shadow({ radius: 4, color: '#1A000000', offsetX: 0, offsetY: 2 })
}
}, (product: Product) => product.id.toString())
}
.padding(16)
.width('100%')
.height('100%')
.backgroundColor('#F8F8F8')
}
}
}
注意事项:
- ForEach的第三个参数是键值生成函数,必须为每个列表项提供唯一的键值
- 对于对象数组,建议使用对象的唯一标识符作为键值
- 如果没有提供合适的键值,列表的更新性能会受到影响
四、列表交互与事件处理
4.1 点击事件处理
为列表项添加点击交互:
@Entry
@Component
struct InteractiveListExample {
private messages: string[] = [
'早上好,今天天气不错',
'下午有个重要的会议',
'记得完成项目报告',
'晚上7点健身房见'
]
build() {
Column() {
List({ space: 1 }) {
ForEach(this.messages, (message: string, index: number) => {
ListItem() {
Row() {
Text(`消息 ${index + 1}`)
.fontSize(16)
.fontWeight(FontWeight.Medium)
Text(message)
.fontSize(14)
.fontColor('#666666')
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.layoutWeight(1)
}
.padding(16)
.width('100%')
}
.onClick(() => {
// 处理点击事件
console.log(`点击了第${index + 1}条消息: ${message}`)
// 在实际应用中,这里通常会跳转到详情页面或执行其他操作
})
}, (message: string, index: number) => index.toString())
}
.width('100%')
.height('100%')
}
}
}
4.2 长按事件与滑动操作
@Entry
@Component
struct AdvancedInteractionList {
@State private tasks: string[] = [
'完成HarmonyOS学习',
'编写项目文档',
'代码评审',
'团队会议',
'产品需求分析'
]
build() {
Column() {
List({ space: 8 }) {
ForEach(this.tasks, (task: string, index: number) => {
ListItem() {
Text(task)
.fontSize(18)
.padding(16)
.width('100%')
.backgroundColor(Color.White)
.borderRadius(8)
}
.onClick(() => {
console.log(`开始任务: ${task}`)
})
.onLongPress(() => {
console.log(`长按任务: ${task}`)
// 显示删除确认对话框等
})
.swipeAction({
end: this.DeleteButton(index)
})
}, (task: string, index: number) => index.toString())
}
.width('100%')
.height('100%')
.padding(16)
.backgroundColor('#F5F5F5')
}
}
@Builder DeleteButton(index: number) {
Button('删除')
.backgroundColor(Color.Red)
.fontColor(Color.White)
.width(80)
.height('100%')
.onClick(() => {
// 删除对应的任务
this.tasks.splice(index, 1)
this.tasks = [...this.tasks] // 触发UI更新
})
}
}
五、自定义列表项布局
5.1 复杂列表项设计
实际应用中的列表项通常包含图片、文本等多种元素:
class Contact {
id: string
name: string
phone: string
avatar: Resource
online: boolean
constructor(id: string, name: string, phone: string, avatar: Resource, online: boolean) {
this.id = id
this.name = name
this.phone = phone
this.avatar = avatar
this.online = online
}
}
@Entry
@Component
struct ContactListExample {
private contacts: Contact[] = [
new Contact('1', '张三', '138****1234', $r('app.media.avatar1'), true),
new Contact('2', '李四', '139****5678', $r('app.media.avatar2'), false),
new Contact('3', '王五', '136****9012', $r('app.media.avatar3'), true)
]
build() {
Column() {
List({ space: 1 }) {
ForEach(this.contacts, (contact: Contact) => {
ListItem() {
Row({ space: 12 }) {
// 头像
Stack() {
Image(contact.avatar)
.width(50)
.height(50)
.borderRadius(25)
// 在线状态指示器
if (contact.online) {
Circle({ width: 12, height: 12 })
.fill('#52C41A')
.position({ x: 38, y: 38 })
.border({ width: 2, color: Color.White })
}
}
.width(50)
.height(50)
// 联系人信息
Column({ space: 4 }) {
Text(contact.name)
.fontSize(18)
.fontColor(Color.Black)
.fontWeight(FontWeight.Medium)
.width('100%')
Text(contact.phone)
.fontSize(14)
.fontColor('#666666')
.width('100%')
}
.layoutWeight(1)
// 操作按钮
Image($r('app.media.ic_call'))
.width(24)
.height(24)
.onClick(() => {
console.log(`呼叫 ${contact.name}`)
})
}
.padding(16)
.width('100%')
}
}, (contact: Contact) => contact.id)
}
.width('100%')
.height('100%')
}
}
}
六、列表性能优化
6.1 使用LazyForEach处理大数据集
当列表数据量很大时,使用LazyForEach可以显著提升性能:
// 数据源实现接口
class MyDataSource implements IDataSource {
private data: string[] = []
private listeners: DataChangeListener[] = []
constructor(data: string[]) {
this.data = data
}
totalCount(): number {
return this.data.length
}
getData(index: number): string {
return this.data[index]
}
registerDataChangeListener(listener: DataChangeListener): void {
this.listeners.push(listener)
}
unregisterDataChangeListener(listener: DataChangeListener): void {
const index = this.listeners.indexOf(listener)
if (index >= 0) {
this.listeners.splice(index, 1)
}
}
}
@Entry
@Component
struct LargeListExample {
private dataSource: MyDataSource = new MyDataSource(
Array.from({ length: 1000 }, (_, i) => `列表项 ${i + 1}`)
)
build() {
Column() {
List({ space: 1 }) {
LazyForEach(this.dataSource, (item: string) => {
ListItem() {
Text(item)
.fontSize(16)
.padding(12)
.width('100%')
}
}, (item: string) => item)
}
.width('100%')
.height('100%')
}
}
}
6.2 列表性能优化技巧
- 使用合适的键值:为每个列表项提供稳定且唯一的键值
- 避免复杂布局:简化列表项的布局层次
- 图片优化:对列表中的图片进行适当压缩和缓存
- 分页加载:大数据集采用分页加载策略
- 虚拟化渲染:List组件默认支持,无需额外配置
七、实际开发中的注意事项
7.1 常见问题与解决方案
问题1:列表滚动卡顿
- 原因:列表项布局过于复杂或数据绑定效率低
- 解决方案:
- 使用LazyForEach替代ForEach处理大数据集
- 简化列表项布局结构
- 避免在列表项中使用过于复杂的计算
问题2:列表项状态异常
- 原因:键值不唯一或状态管理不当
- 解决方案:
- 确保每个列表项有唯一的键值
- 合理使用@State、@Prop等装饰器管理状态
问题3:内存泄漏
- 原因:事件监听器未正确移除
- 解决方案:
- 及时移除不需要的事件监听
- 使用弱引用或适当的作用域管理
7.2 版本兼容性说明
- List组件从API version 7开始支持
- swipeAction属性从API version 9开始支持
- LazyForEach从API version 8开始支持
- 建议在开发时关注目标设备的HarmonyOS版本
八、完整实战案例:任务管理应用
让我们结合所学知识,创建一个完整的任务管理应用:
class Task {
id: string
title: string
completed: boolean
priority: number // 1-高, 2-中, 3-低
createTime: number
constructor(id: string, title: string, priority: number) {
this.id = id
this.title = title
this.completed = false
this.priority = priority
this.createTime = new Date().getTime()
}
}
@Entry
@Component
struct TaskManagerApp {
@State private tasks: Task[] = [
new Task('1', '学习HarmonyOS开发', 1),
new Task('2', '完成项目文档', 2),
new Task('3', '购买生活用品', 3)
]
@State private newTaskTitle: string = ''
build() {
Column() {
// 标题
Text('任务管理')
.fontSize(24)
.fontWeight(FontWeight.Bold)
.margin({ top: 20, bottom: 20 })
// 添加新任务
Row({ space: 8 }) {
TextInput({ placeholder: '输入新任务...', text: this.newTaskTitle })
.layoutWeight(1)
.onChange((value: string) => {
this.newTaskTitle = value
})
Button('添加')
.backgroundColor('#1890FF')
.fontColor(Color.White)
.onClick(() => {
if (this.newTaskTitle.trim()) {
const newTask = new Task(
Date.now().toString(),
this.newTaskTitle,
2
)
this.tasks = [newTask, ...this.tasks]
this.newTaskTitle = ''
}
})
}
.padding(16)
.width('100%')
// 任务列表
List({ space: 8 }) {
ForEach(this.tasks, (task: Task) => {
ListItem() {
this.TaskItem(task)
}
.swipeAction({
end: this.DeleteTaskButton(task.id)
})
}, (task: Task) => task.id)
}
.layoutWeight(1)
.width('100%')
.padding(16)
}
.width('100%')
.height('100%')
.backgroundColor('#F8F9FA')
}
@Builder
TaskItem(task: Task) {
Row({ space: 12 }) {
// 完成状态复选框
Image(task.completed ? $r('app.media.ic_checked') : $r('app.media.ic_unchecked'))
.width(24)
.height(24)
.onClick(() => {
task.completed = !task.completed
this.tasks = [...this.tasks]
})
// 任务内容
Column({ space: 4 }) {
Text(task.title)
.fontSize(16)
.fontColor(task.completed ? '#999999' : Color.Black)
.decoration({ type: task.completed ? TextDecorationType.LineThrough : TextDecorationType.None })
// 优先级标签
Row() {
Text(this.getPriorityText(task.priority))
.fontSize(12)
.fontColor(this.getPriorityColor(task.priority))
}
.padding({ left: 4, right: 4, top: 2, bottom: 2 })
.backgroundColor(this.getPriorityBgColor(task.priority))
.borderRadius(4)
}
.layoutWeight(1)
}
.padding(16)
.width('100%')
.backgroundColor(Color.White)
.borderRadius(8)
.shadow({ radius: 2, color: '#1A000000', offsetX: 0, offsetY: 1 })
}
@Builder
DeleteTaskButton(taskId: string) {
Button('删除')
.backgroundColor(Color.Red)
.fontColor(Color.White)
.width(80)
.height('100%')
.onClick(() => {
this.tasks = this.tasks.filter(task => task.id !== taskId)
})
}
private getPriorityText(priority: number): string {
switch (priority) {
case 1: return '高优先级'
case 2: return '中优先级'
case 3: return '低优先级'
default: return '普通'
}
}
private getPriorityColor(priority: number): string {
switch (priority) {
case 1: return '#CF1322'
case 2: return '#FA8C16'
case 3: return '#52C41A'
default: return '#666666'
}
}
private getPriorityBgColor(priority: number): string {
switch (priority) {
case 1: return '#FFF1F0'
case 2: return '#FFF7E6'
case 3: return '#F6FFED'
default: return '#F5F5F5'
}
}
}
总结
通过本文的学习,你应该已经掌握了:
- List组件的基础用法和核心属性
- 使用ForEach和LazyForEach进行数据绑定
- 列表交互事件的处理方法
- 复杂列表项的自定义布局设计
- 列表性能优化的实用技巧
- 实际开发中的注意事项和最佳实践
List组件是HarmonyOS应用开发中不可或缺的重要组件,熟练掌握它的使用将极大提升你的开发效率和应用的性能表现。建议在实际项目中多加练习,不断探索List组件的更多高级特性。
下一步学习建议:
- 学习Grid网格布局组件
- 探索List与Navigation的组合使用
- 了解自定义组件在列表中的应用
- 研究列表的动画和过渡效果
Happy Coding!
需要参加鸿蒙认证的请点击 鸿蒙认证链接

浙公网安备 33010602011771号