HarmonyOS ArkTS List 列表组件使用指南
本文基于 HarmonyOS NEXT 开发环境,详细讲解 ArkTS 中 List 列表容器组件的核心概念、常用 API 及实战用法。通过一个完整的简约示例,帮助你从零掌握 List 组件的开发流程。
效果
一、List 组件概述
1.1 什么是 List
List是 ArkUI 框架提供的列表容器组件,用于包含一系列相同宽度的列表项(ListItem)。它天然支持滚动,适合连续、多行呈现同类数据,例如联系人列表、消息列表、商品清单等。
核心特性:
| 特性 | 说明 |
|---|---|
| 自动滚动 | 子项高度超出容器时自动出现滚动效果 |
| 子组件限制 | 仅支持ListItem、ListItemGroup及自定义组件 |
| 布局方向 | 默认垂直排列,可通过listDirection设为水平 |
| 数据驱动 | 配合ForEach/LazyForEach实现动态渲染 |
1.2 基本结构
List(){ListItem(){Text('列表项 1')}ListItem(){Text('列表项 2')}ListItem(){Text('列表项 3')}}注意:每个
ListItem内部只能有一个根节点组件。如果需要多个组件组合,必须将它们包裹在Row、Column、Flex等容器组件内。
二、核心 API 详解
2.1 构造参数
| 参数 | 类型 | 说明 |
|---|---|---|
space | number | string | Resource | 列表项之间的间距 |
initialIndex | number | 初始显示的列表项索引 |
scroller | Scroller | 可滚动组件的控制器,用于程序化控制滚动 |
2.2 常用属性
| 属性 | 说明 |
|---|---|
.listDirection(direction) | 排列方向:Axis.Vertical(默认)或Axis.Horizontal |
.scrollBar(state) | 滚动条状态:BarState.On/BarState.Off/BarState.Auto |
.alignListItem(align) | 列表项对齐方式:ListItemAlign.Start/Center/End |
.cachedCount(count) | 列表项缓存数量,优化长列表滚动性能 |
.layoutWeight(weight) | 在父容器中按权重分配剩余空间 |
.divider(divider) | 列表项之间的分割线样式 |
.edgeEffect(effect) | 滑动到边缘时的效果:EdgeEffect.Spring/None |
2.3 常用事件
| 事件 | 说明 |
|---|---|
.onAppear() | 列表项首次出现时触发 |
.onDisAppear() | 列表项消失时触发 |
.onScrollIndex(index) | 滑动到指定索引时触发 |
.onReachStart() | 滑动到列表顶部时触发 |
.onReachEnd() | 滑动到底部时触发 |
三、动态渲染:ForEach 与 LazyForEach
3.1 ForEach 循环渲染
ForEach是声明式循环渲染函数,它遍历数据源并为每一项创建对应的ListItem。当数据源与@State联动时,数据变化会自动触发 UI 刷新。
@Stateitems:string[]=['苹果','香蕉','橙子']List(){ForEach(this.items,(item:string)=>{ListItem(){Text(item).fontSize(16)}})}ForEach 三个参数说明:
| 参数 | 说明 |
|---|---|
arr | 数据源数组 |
itemGenerator | 列表项生成函数(item, index) => void |
keyGenerator | 唯一键生成函数(item, index) => string(可选但推荐) |
最佳实践:始终提供
keyGenerator,它可以帮助框架精确识别数据变化,避免不必要的组件重建,提升性能。
3.2 LazyForEach 懒加载
当列表数据量很大时,使用LazyForEach配合IDataSource接口实现按需加载,只渲染可见区域的列表项,大幅提升性能。
List(){LazyForEach(this.dataSource,(item:DataItem)=>{ListItem(){Text(item.title)}},(item:DataItem)=>item.id.toString())}.cachedCount(5)// 缓存屏幕外 5 个列表项四、分组列表:ListItemGroup
ListItemGroup用于将列表项分组显示,配合sticky属性可实现分组标题吸顶效果。
List(){ListItemGroup({header:this.groupHeader('水果')}){ForEach(this.fruits,(item:string)=>{ListItem(){Text(item)}})}ListItemGroup({header:this.groupHeader('蔬菜')}){ForEach(this.vegetables,(item:string)=>{ListItem(){Text(item)}})}}.sticky(StickyStyle.Header)@BuildergroupHeader(title:string){Text(title).fontSize(16).fontWeight(FontWeight.Bold).backgroundColor('#F5F5F5').width('100%').padding(12)}五、完整实战示例:课程清单
下面通过一个完整的示例,演示如何使用 List 组件构建一个课程清单页面。
5.1 效果说明
- 顶部显示标题栏
- 中间使用 List 展示课程列表,每项包含课程名称、讲师和时长
- 支持滚动、分割线显示
- 列表项带有选中高亮效果
5.2 完整代码
// 数据模型classCourseItem{id:numbername:stringteacher:stringduration:stringconstructor(id:number,name:string,teacher:string,duration:string){this.id=idthis.name=namethis.teacher=teacherthis.duration=duration}}@Entry@Componentstruct CourseListPage{@StateselectedIndex:number=-1@StatecourseList:CourseItem[]=[newCourseItem(0,'HarmonyOS 应用开发入门','张老师','45分钟'),newCourseItem(1,'ArkTS 语言基础','李老师','60分钟'),newCourseItem(2,'ArkUI 组件详解','王老师','50分钟'),newCourseItem(3,'状态管理进阶','赵老师','55分钟'),newCourseItem(4,'路由与导航','孙老师','40分钟'),newCourseItem(5,'网络请求与数据持久化','周老师','65分钟'),newCourseItem(6,'性能优化实战','吴老师','70分钟'),]build(){Column(){// 标题栏Text('课程清单').fontSize(22).fontWeight(FontWeight.Bold).width('100%').padding({left:16,top:16,bottom:12})// 列表区域List({space:0}){ForEach(this.courseList,(item:CourseItem,index:number)=>{ListItem(){Row(){// 序号圆圈Text(`${index+1}`).fontSize(14).fontColor(Color.White).width(28).height(28).borderRadius(14).backgroundColor('#4FC3F7').textAlign(TextAlign.Center)// 课程信息Column(){Text(item.name).fontSize(16).fontWeight(FontWeight.Medium).maxLines(1).textOverflow({overflow:TextOverflow.Ellipsis})Row({space:12}){Text(`讲师:${item.teacher}`).fontSize(13).fontColor('#888888')Text(`时长:${item.duration}`).fontSize(13).fontColor('#888888')}.margin({top:4})}.layoutWeight(1).alignItems(HorizontalAlign.Start).margin({left:12})}.width('100%').padding({left:16,right:16,top:12,bottom:12}).backgroundColor(this.selectedIndex===item.id?'#E3F2FD':Color.White)}.onClick(()=>{this.selectedIndex=item.id})},(item:CourseItem)=>item.id.toString())}.width('100%').layoutWeight(1).scrollBar(BarState.Off).edgeEffect(EdgeEffect.Spring).divider({strokeWidth:0.5,color:'#E0E0E0',startMargin:56,endMargin:16})}.width('100%').height('100%').backgroundColor('#FAFAFA')}}5.3 关键代码解析
(1)数据驱动渲染
使用@State装饰courseList数组,配合ForEach实现数据驱动的列表渲染。当数组发生变化时,UI 会自动刷新。
(2)选中状态高亮
通过@State selectedIndex记录当前选中的课程 ID,在ListItem中根据this.selectedIndex === item.id动态设置背景色。
(3)分割线配置
.divider({strokeWidth:0.5,color:'#E0E0E0',startMargin:56,// 左侧留白,与序号圆圈对齐endMargin:16})startMargin和endMargin让分割线不与序号圆圈重叠,视觉上更加整洁。
(4)边缘回弹效果
.edgeEffect(EdgeEffect.Spring)为列表添加了弹性回弹效果,提升用户的滑动体验。
六、最佳实践总结
6.1 性能优化
| 优化手段 | 说明 |
|---|---|
使用LazyForEach | 大数据量列表按需加载,避免一次性创建所有组件 |
设置cachedCount | 缓存屏幕外的列表项,减少快速滑动时的创建开销 |
提供keyGenerator | 帮助框架精确识别变化项,减少不必要的组件重建 |
避免在ListItem中使用复杂嵌套 | 减少布局层级,提升渲染速度 |
6.2 常见问题
| 问题 | 原因及解决方案 |
|---|---|
| 列表项不显示 | 检查ListItem内是否只有一个根节点组件 |
| 数据更新后 UI 不刷新 | 使用@State装饰数据源,或通过keyGenerator精确控制刷新 |
| 滚动不流畅 | 使用LazyForEach替代ForEach,设置合理的cachedCount |
| 水平列表无法滚动 | 确保设置了.listDirection(Axis.Horizontal)且有足够宽度 |
6.3 使用建议
- 简单列表用
ForEach:数据量在几十条以内,直接使用ForEach即可。 - 长列表用
LazyForEach:数据量较大时,配合IDataSource接口实现懒加载。 - 分组场景用
ListItemGroup:配合sticky属性实现吸顶效果,适合通讯录、分类列表等场景。 - 善用
ListScroller:通过scroller参数可以在代码中控制列表滚动到指定位置。
七、参考链接
- List 官方 API 文档
- ForEach 循环渲染
- LazyForEach 懒加载