鸿蒙学习实战之路:HarmonyOS 通用列表流程使用指南
HarmonyOS 通用列表流程使用指南
参考文档
概述
列表流是采用以"行"为单位进行内容排列的布局形式,每"行"列表项通过文本、图片等不同形式的组合,高效地显示结构化的信息,当列表项内容超过屏幕大小时,可以提供滚动功能。
列表流具有以下特点:
- 排版整齐
- 重点突出
- 对比方便
- 浏览速度快
常见使用场景包括:应用首页、通讯录、音乐列表、购物清单等。
在 HarmonyOS 中,列表流主要使用 List 组件,按垂直方向线性排列子组件 ListItemGroup 或 ListItem,混合渲染任意数量的图文视图,从而构建列表内容。
基础组件
List 组件
List 是最基础的列表容器组件,用于创建可滚动的列表。
import { Column, List, ListItem, Text } from '@ohos/components';
@Entry
@Component
struct BasicListExample {
private listData: string[] = ['列表项1', '列表项2', '列表项3', '列表项4', '列表项5'];
build() {
Column() {
List({
scroller: null,
space: 20
})
.width('100%')
.height('100%')
.onScrollIndex((start: number, end: number) => {
// 滚动事件处理
})
.onReachStart(() => {
// 滚动到顶部
})
.onReachEnd(() => {
// 滚动到底部,可用于加载更多
})
.onScrollStop(() => {
// 滚动停止
})
{
ForEach(this.listData, (item) => {
ListItem() {
Text(item)
.width('100%')
.height(60)
.textAlign(TextAlign.Center)
.fontSize(16)
}
.backgroundColor('#f0f0f0')
.margin({ left: 16, right: 16 })
}, item => item)
}
}
.padding(16)
}
}
常见列表流场景实现
1. 多类型列表项场景
场景描述
List 组件作为整个首页长列表的容器,通过 ListItem 对不同模块进行视图界面定制,常用于门户首页、商城首页等多类型视图展示的列表信息流场景。
实现原理
根据列表内部各部分视图对应数据类型的区别,渲染不同的 ListItem 子组件。
import { Column, List, ListItem, Text, Image, Grid, GridItem } from '@ohos/components';
@Entry
@Component
struct MultiTypeListExample {
// 模拟数据
private bannerData = {
images: ['banner1.png', 'banner2.png'],
type: 'banner'
};
private recommendData = [
{ id: 1, title: '推荐内容1', image: 'rec1.png' },
{ id: 2, title: '推荐内容2', image: 'rec2.png' },
{ id: 3, title: '推荐内容3', image: 'rec3.png' },
{ id: 4, title: '推荐内容4', image: 'rec4.png' },
];
private articleData = [
{ id: 1, title: '文章标题1', desc: '文章描述1', type: 'article' },
{ id: 2, title: '文章标题2', desc: '文章描述2', type: 'article' },
];
build() {
Column() {
List() {
// Banner类型列表项
ListItem() {
Column() {
Text('Banner区域')
.fontSize(18)
.fontWeight(FontWeight.Bold)
// 这里可以放置轮播图组件
Image(this.bannerData.images[0])
.width('100%')
.height(200)
.borderRadius(12)
}
.padding(16)
}
// 推荐内容类型列表项
ListItem() {
Column() {
Text('推荐内容')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 16 })
Grid() {
ForEach(this.recommendData, (item) => {
GridItem() {
Column() {
Image(item.image)
.width('100%')
.height(120)
.aspectRatio(1)
Text(item.title)
.fontSize(14)
.margin({ top: 8 })
}
}
}, item => item.id)
}
.columnsTemplate('1fr 1fr')
.columnsGap(16)
.rowsGap(16)
}
.padding(16)
}
// 文章列表类型列表项
ListItem() {
Column() {
Text('最新文章')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 16 })
ForEach(this.articleData, (item) => {
Column() {
Text(item.title)
.fontSize(16)
.fontWeight(FontWeight.Medium)
Text(item.desc)
.fontSize(14)
.fontColor('#666666')
.margin({ top: 8 })
}
.padding(16)
.backgroundColor('#f5f5f5')
.borderRadius(8)
.margin({ bottom: 12 })
}, item => item.id)
}
.padding(16)
}
}
}
}
}
2. Tabs 吸顶场景
场景描述
当页面包含 Tabs 组件时,实现 Tabs 在滚动到顶部后保持吸顶状态,常用于分类浏览、数据筛选等场景。
实现原理
使用 List 组件的 sticky 属性实现元素吸顶效果。
import { Column, List, ListItem, Tabs, TabContent, Text } from '@ohos/components';
@Entry
@Component
struct StickyTabsExample {
private tabList: string[] = ['推荐', '关注', '热门', '最新'];
build() {
Column() {
// 页面顶部内容
Column() {
Text('页面标题')
.fontSize(24)
.fontWeight(FontWeight.Bold)
.padding(16)
}
// 可吸顶的Tabs组件
Tabs() {
ForEach(this.tabList, (tab) => {
TabContent() {
List() {
ListItem() {
Text(`${tab}内容列表`)
.fontSize(16)
.padding(20)
}
// 生成更多列表项
ForEach(Array.from({ length: 20 }), (_, index) => {
ListItem() {
Text(`${tab}内容 ${index + 1}`)
.fontSize(16)
.padding(20)
.backgroundColor('#f5f5f5')
.margin({ left: 16, right: 16, top: 12 })
.borderRadius(8)
}
})
}
}
.tabBar(tab)
})
}
.width('100%')
.height('80%')
.barMode(BarMode.Scrollable)
.scrollable(true)
}
}
}
3. 分组吸顶场景
场景描述
列表内容按分组展示,每个分组的标题在滚动到顶部时保持吸顶状态,常用于联系人列表、城市选择等场景。
实现原理
使用 ListItemGroup 组件创建分组,并设置 sticky 属性实现分组标题吸顶。
import { Column, List, ListItemGroup, ListItem, Text } from '@ohos/components';
@Entry
@Component
struct GroupStickyExample {
// 模拟分组数据
private groupData = [
{
title: 'A',
items: ['Alice', 'Amy', 'Anna']
},
{
title: 'B',
items: ['Bob', 'Bill']
},
{
title: 'C',
items: ['Charlie', 'Cathy', 'Carol']
}
];
build() {
Column() {
Text('联系人列表')
.fontSize(24)
.fontWeight(FontWeight.Bold)
.padding(16)
List() {
ForEach(this.groupData, (group) => {
ListItemGroup({
header: () => {
// 分组标题
return (
Text(group.title)
.fontSize(18)
.fontWeight(FontWeight.Bold)
.backgroundColor('#e0e0e0')
.padding(12)
.width('100%')
)
},
footer: () => {
// 分组底部
return null;
},
sticky: ListItemStickyStyle.Header
})
{
// 分组内的列表项
ForEach(group.items, (item) => {
ListItem() {
Text(item)
.fontSize(16)
.padding(16)
.width('100%')
}
.borderBottom({ width: 1, color: '#f0f0f0' })
})
}
})
}
.width('100%')
.height('80%')
}
}
}
4. 二级联动场景
场景描述
左侧为分类列表,右侧为对应分类下的内容列表,滚动右侧内容时左侧分类同步高亮显示,点击左侧分类时右侧内容滚动到对应位置,常用于商品分类、点餐应用等场景。
实现原理
通过监听左右两侧列表的滚动和点击事件,实现联动效果。
import { Column, Row, List, ListItem, Text, Scroll, ScrollController } from '@ohos/components';
@Entry
@Component
struct TwoLevelLinkageExample {
private categories = ['分类1', '分类2', '分类3', '分类4', '分类5'];
private selectedIndex: number = 0;
private scrollController: ScrollController = new ScrollController();
// 模拟分类内容数据
private categoryData = {
'分类1': ['商品1-1', '商品1-2', '商品1-3', '商品1-4'],
'分类2': ['商品2-1', '商品2-2'],
'分类3': ['商品3-1', '商品3-2', '商品3-3'],
'分类4': ['商品4-1', '商品4-2', '商品4-3', '商品4-4', '商品4-5'],
'分类5': ['商品5-1', '商品5-2']
};
// 点击分类处理函数
onCategoryClick(index: number) {
this.selectedIndex = index;
// 滚动到对应位置
this.scrollController.scrollTo({ xOffset: 0, yOffset: 0 });
}
build() {
Column() {
Row() {
// 左侧分类列表
List() {
ForEach(this.categories, (category, index) => {
ListItem() {
Text(category)
.fontSize(16)
.padding(16)
.width('100%')
.backgroundColor(this.selectedIndex === index ? '#e6f7ff' : '#ffffff')
.fontColor(this.selectedIndex === index ? '#1890ff' : '#000000')
.onClick(() => this.onCategoryClick(index))
}
.borderBottom({ width: 1, color: '#f0f0f0' })
})
}
.width('30%')
.height('80%')
// 右侧内容列表
Scroll(this.scrollController) {
Column() {
ForEach(this.categoryData[this.categories[this.selectedIndex]], (item) => {
Text(item)
.fontSize(16)
.padding(16)
.width('100%')
.backgroundColor('#f5f5f5')
.margin({ bottom: 12 })
.borderRadius(8)
})
}
.padding(16)
}
.width('70%')
.height('80%')
}
}
}
}
性能优化
1. 虚拟化渲染
HarmonyOS 的 List 组件默认开启虚拟化渲染,只会渲染可视区域内的列表项,以及少量缓冲区的列表项,可以有效减少内存占用和提高渲染性能。
2. 懒加载
对于列表中的图片等资源,可以实现懒加载,只在图片即将进入可视区域时再加载。
import { Image } from '@ohos/components';
// 自定义懒加载图片组件
@Component
struct LazyLoadImage {
@Prop src: string;
private isLoaded: boolean = false;
// 当组件可见时加载图片
onVisibleChanged(visible: boolean) {
if (visible && !this.isLoaded) {
this.isLoaded = true;
}
}
build() {
Image(this.isLoaded ? this.src : '')
.onVisible(this.onVisibleChanged)
.width('100%')
.height(200)
}
}
3. 避免不必要的重渲染
使用memo、@Watch等机制,避免组件不必要的重渲染。
// 使用memo优化子组件
const MemoizedListItem = memo((props: { data: any }) => {
return (
ListItem() {
Text(props.data.title)
.fontSize(16)
.padding(16)
}
);
});
注意事项与最佳实践
1. 列表项高度设置
为了提高渲染性能,建议为列表项设置固定高度或最大高度,避免动态高度导致的布局重计算。
2. 大数据量处理
当列表数据量较大时:
- 实现分页加载
- 使用虚拟列表
- 避免在滚动过程中执行复杂计算
3. 事件处理优化
- 使用事件委托减少事件监听器数量
- 避免在
onScroll等频繁触发的事件中执行耗时操作
List()
.onScroll(() => {
// 避免在这里执行复杂计算
})
// 可以使用节流处理
.onScrollThrottle(300, () => {
// 每300ms最多执行一次
});
4. 列表缓存
对于频繁访问的列表数据,可以实现缓存机制,减少重复请求。
常见问题解答
Q: List 组件和 Scroll 组件有什么区别?
A: List 组件专为列表数据展示优化,支持虚拟化渲染、分组、粘性头部等功能,性能更好;Scroll 组件是通用的滚动容器,功能更灵活但性能相对较差。
Q: 如何实现列表的下拉刷新和上拉加载更多?
A: 可以使用 Refresh 组件实现下拉刷新,结合 List 的 onReachEnd 事件实现上拉加载更多。
Refresh({
refreshing: this.isRefreshing,
onRefresh: () => {
// 下拉刷新逻辑
this.loadData();
},
});
{
List().onReachEnd(() => {
// 上拉加载更多逻辑
this.loadMoreData();
});
}
Q: 如何优化长列表的性能?
A:
- 使用固定高度的列表项
- 开启虚拟化渲染
- 实现懒加载
- 避免在滚动过程中执行复杂操作
- 使用 memo 优化组件渲染
总结
HarmonyOS 的列表流开发主要使用 List 组件,可以实现多种复杂的列表场景。通过本文介绍的多类型列表项、Tabs 吸顶、分组吸顶和二级联动等场景的实现方法,开发者可以快速构建出功能丰富、性能优良的列表页面。在实际开发中,还需要注意性能优化和用户体验,确保列表滚动流畅,响应迅速。

浙公网安备 33010602011771号