138.[HarmonyOS NEXT 实战案例七:List系列] 多列列表组件实战:打造精美应用推荐页 进阶篇
2025-06-30 22:15:17
104次阅读
0个评论
[HarmonyOS NEXT 实战案例七:List系列] 多列列表组件实战:打造精美应用推荐页 进阶篇
项目已开源,开源地址: https://gitcode.com/nutpi/HarmonyosNextCaseStudyTutorial , 欢迎fork & star
效果演示
一、多列列表的进阶特性
在基础篇中,我们已经学习了如何创建基本的多列应用列表。在本篇教程中,我们将深入探讨多列列表的进阶特性,包括交互功能、布局优化、状态管理等方面。
1.1 多列列表的进阶属性
属性 | 说明 | 用途 |
---|---|---|
alignListItem | 设置列表项对齐方式 | 控制列表项在交叉轴上的对齐方式 |
scrollBar | 设置滚动条样式 | 控制滚动条的显示和外观 |
edgeEffect | 设置边缘效果 | 控制列表到达边缘时的视觉反馈 |
chainAnimation | 设置链式动画 | 控制列表项的连锁动画效果 |
multiSelectable | 设置多选模式 | 允许用户选择多个列表项 |
cachedCount | 设置缓存数量 | 控制预加载的列表项数量 |
1.2 多列列表的交互特性
特性 | 说明 | 用途 |
---|---|---|
onItemClick | 列表项点击事件 | 监听列表项的点击状态 |
onScroll | 滚动事件 | 监听列表的滚动状态 |
onReachStart/End | 到达边缘事件 | 监听列表到达开始/结束位置 |
onScrollStop | 滚动停止事件 | 监听列表停止滚动的状态 |
二、应用推荐页的交互增强
在基础版本的应用推荐页基础上,我们可以添加更多的交互功能,使应用推荐页更加实用和用户友好。
2.1 添加应用点击详情功能
我们可以为应用列表项添加点击事件,点击后显示应用的详细信息:
@Component
export struct AdvancedMultiColumnList {
// 应用数据
private apps: AppType[] = [...] // 与基础版相同
// 当前选中的应用索引
@State selectedIndex: number = -1
// 是否显示详情
@State showDetail: boolean = false
build() {
Stack() {
Column() {
// 标题栏和底部导航栏(与基础版相同)
// 多列应用列表
List() {
ForEach(this.apps, (app:AppType, index: number) => {
ListItem() {
Column() {
// 应用图标
Image(app.icon)
.width(60)
.height(60)
.borderRadius(12)
// 应用名称
Text(app.name)
.width(100)
.fontSize(14)
.margin({ top: 8 })
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
// 下载量
Text(app.downloads)
.width(100)
.fontSize(12)
.fontColor('#666666')
.margin({ top: 4 })
}
.alignItems(HorizontalAlign.Center)
.width('100%')
.padding(12)
.onClick(() => {
this.selectedIndex = index
this.showDetail = true
})
}
.width('33%') // 每个项目占用1/3的宽度
.padding(8)
})
}
// List属性设置(与基础版相同)
}
// 应用详情层
if (this.showDetail && this.selectedIndex >= 0) {
this.AppDetail()
}
}
.width('100%')
.height('100%')
}
@Builder AppDetail() {
Column() {
// 详情顶栏
Row() {
Button({
type: ButtonType.Circle,
stateEffect: true
}) {
Image($r('app.media.ic_back'))
.width(24)
.height(24)
}
.width(40)
.height(40)
.backgroundColor('rgba(0, 0, 0, 0.05)')
.margin({ right: 16 })
.onClick(() => {
this.showDetail = false
})
Text(this.apps[this.selectedIndex].name)
.fontSize(20)
.fontWeight(FontWeight.Bold)
}
.width('100%')
.height(56)
.padding({ left: 16, right: 16 })
.backgroundColor('#FFFFFF')
// 应用详情内容
Scroll() {
Column() {
// 应用头部信息
Row() {
Image(this.apps[this.selectedIndex].icon)
.width(80)
.height(80)
.borderRadius(16)
.margin({ right: 16 })
Column() {
Text(this.apps[this.selectedIndex].name)
.fontSize(18)
.fontWeight(FontWeight.Bold)
Text(this.apps[this.selectedIndex].downloads)
.fontSize(14)
.fontColor('#666666')
.margin({ top: 4 })
Row() {
Button('安装')
.width(100)
.height(36)
.backgroundColor('#007DFF')
.margin({ top: 8 })
}
}
.alignItems(HorizontalAlign.Start)
.layoutWeight(1)
}
.width('100%')
.padding(16)
// 应用截图
Text('应用截图')
.fontSize(16)
.fontWeight(FontWeight.Bold)
.width('100%')
.padding({ left: 16, top: 16, bottom: 8 })
List() {
ForEach([1, 2, 3, 4], (item) => {
ListItem() {
// 模拟截图
Column() {
Text(`截图 ${item}`)
.width('100%')
.height('100%')
.textAlign(TextAlign.Center)
.backgroundColor('#F0F0F0')
}
.width(240)
.height(400)
.borderRadius(8)
}
.padding({ right: 12 })
})
}
.width('100%')
.height(420)
.listDirection(Axis.Horizontal)
.padding({ left: 16 })
// 应用介绍
Text('应用介绍')
.fontSize(16)
.fontWeight(FontWeight.Bold)
.width('100%')
.padding({ left: 16, top: 16, bottom: 8 })
Text('这是一个示例应用介绍,描述应用的主要功能和特点。实际应用中,这里会显示应用的详细介绍信息,包括功能特点、使用方法、更新日志等内容。')
.fontSize(14)
.width('100%')
.padding({ left: 16, right: 16, bottom: 16 })
}
}
.layoutWeight(1)
}
.width('100%')
.height('100%')
.backgroundColor('#FFFFFF')
}
}
在这个示例中:
- 添加了两个@State装饰的状态变量:selectedIndex和showDetail
- 为列表项的Column容器添加了onClick事件处理函数,点击时更新selectedIndex并显示详情
- 使用Stack组件作为根容器,可以在应用列表上方显示详情层
- 添加了AppDetail Builder函数,用于构建应用详情界面
- 在详情界面中,使用Scroll组件使内容可滚动,并添加了应用头部信息、截图和介绍等内容
2.2 实现应用分类功能
我们可以为应用列表添加分类功能,按照不同类别展示应用:
@Component
export struct AdvancedMultiColumnList {
// 应用数据
private apps: AppType[] = [...] // 与基础版相同
// 应用分类
private categories: string[] = ['全部', '游戏', '工具', '社交', '教育', '娱乐']
// 当前选中的分类索引
@State currentCategoryIndex: number = 0
// 根据分类筛选应用
private getFilteredApps(): AppType[] {
if (this.currentCategoryIndex === 0) {
return this.apps // 返回全部应用
}
// 模拟根据分类筛选应用
// 实际应用中,应该根据应用的分类属性进行筛选
const categoryApps: AppType[] = []
for (let i = 0; i < this.apps.length; i++) {
if (i % this.categories.length === this.currentCategoryIndex) {
categoryApps.push(this.apps[i])
}
}
return categoryApps
}
build() {
Column() {
// 标题栏(与基础版相同)
// 分类选择器
List() {
ForEach(this.categories, (category: string, index: number) => {
ListItem() {
Text(category)
.fontSize(14)
.fontColor(this.currentCategoryIndex === index ? '#007DFF' : '#333333')
.fontWeight(this.currentCategoryIndex === index ? FontWeight.Bold : FontWeight.Normal)
.padding({ left: 16, right: 16, top: 8, bottom: 8 })
.backgroundColor(this.currentCategoryIndex === index ? '#E6F2FF' : 'transparent')
.borderRadius(16)
.onClick(() => {
this.currentCategoryIndex = index
})
}
.padding({ right: 8 })
})
}
.width('100%')
.height(48)
.listDirection(Axis.Horizontal)
.padding({ left: 16 })
// 多列应用列表
List() {
ForEach(this.getFilteredApps(), (app:AppType) => {
// 列表项内容(与基础版相同)
})
}
// List属性设置(与基础版相同)
// 底部导航栏(与基础版相同)
}
// Column属性设置(与基础版相同)
}
}
在这个示例中:
- 添加了categories数组,包含不同的应用分类
- 添加了currentCategoryIndex状态变量,用于跟踪当前选中的分类
- 实现了getFilteredApps方法,根据当前选中的分类筛选应用
- 添加了一个水平方向的List组件作为分类选择器,显示不同的分类选项
- 为分类选项添加了点击事件处理函数,点击时更新currentCategoryIndex
- 在应用列表中使用getFilteredApps方法获取筛选后的应用数据
2.3 实现应用搜索功能
我们可以为应用列表添加搜索功能,根据关键字搜索应用:
@Component
export struct AdvancedMultiColumnList {
// 应用数据
private apps: AppType[] = [...] // 与基础版相同
// 搜索关键字
@State searchKey: string = ''
// 根据关键字搜索应用
private getSearchedApps(): AppType[] {
if (!this.searchKey) {
return this.apps // 返回全部应用
}
// 根据关键字搜索应用名称
return this.apps.filter(app =>
app.name.toLowerCase().includes(this.searchKey.toLowerCase())
)
}
build() {
Column() {
// 标题栏
Row() {
Text('应用推荐')
.fontSize(24)
.fontWeight(FontWeight.Bold)
}
.width('100%')
.height(56)
.padding({ left: 16 })
.backgroundColor('#F1F3F5')
// 搜索框
Row() {
Image($r('app.media.ic_search'))
.width(24)
.height(24)
.margin({ right: 8 })
TextInput({ placeholder: '搜索应用', text: this.searchKey })
.layoutWeight(1)
.height(40)
.backgroundColor('transparent')
.onChange((value: string) => {
this.searchKey = value
})
if (this.searchKey) {
Button({
type: ButtonType.Circle,
stateEffect: true
}) {
Image($r('app.media.ic_clear'))
.width(16)
.height(16)
}
.width(24)
.height(24)
.backgroundColor('rgba(0, 0, 0, 0.05)')
.margin({ left: 8 })
.onClick(() => {
this.searchKey = ''
})
}
}
.width('100%')
.height(56)
.padding({ left: 16, right: 16 })
.backgroundColor('#FFFFFF')
.borderColor('#E5E5E5')
.borderWidth({ bottom: 1 })
// 多列应用列表
if (this.getSearchedApps().length > 0) {
List() {
ForEach(this.getSearchedApps(), (app:AppType) => {
// 列表项内容(与基础版相同)
})
}
// List属性设置(与基础版相同)
} else {
// 无搜索结果提示
Column() {
Image($r('app.media.ic_no_result'))
.width(100)
.height(100)
.margin({ bottom: 16 })
Text('没有找到相关应用')
.fontSize(16)
.fontColor('#999999')
}
.width('100%')
.layoutWeight(1)
.justifyContent(FlexAlign.Center)
}
// 底部导航栏(与基础版相同)
}
// Column属性设置(与基础版相同)
}
}
在这个示例中:
- 添加了searchKey状态变量,用于存储搜索关键字
- 实现了getSearchedApps方法,根据搜索关键字筛选应用
- 添加了搜索框,包含搜索图标、TextInput组件和清除按钮
- 为TextInput组件添加了onChange事件处理函数,更新searchKey
- 为清除按钮添加了onClick事件处理函数,清空searchKey
- 根据搜索结果是否为空显示不同的内容,如果为空则显示无搜索结果提示
三、多列列表的布局优化
除了基本的布局外,我们还可以对多列列表进行更多的布局优化,使其更加美观和实用。
3.1 响应式列数设置
我们可以根据屏幕宽度动态调整列表的列数,使其在不同设备上都能有良好的显示效果:
@Component
export struct AdvancedMultiColumnList {
// 应用数据和其他属性
// 屏幕宽度
@State screenWidth: number = 0
// 根据屏幕宽度计算列数
private getColumnCount(): number {
if (this.screenWidth <= 320) {
return 2 // 窄屏设备显示2列
} else if (this.screenWidth <= 600) {
return 3 // 中等宽度设备显示3列
} else {
return 4 // 宽屏设备显示4列
}
}
// 根据列数计算列表项宽度
private getItemWidth(): string {
const columnCount = this.getColumnCount()
return `${100 / columnCount}%`
}
aboutToAppear() {
// 获取屏幕宽度
this.screenWidth = px2vp(this.context.width)
}
build() {
Column() {
// 标题栏和其他内容(与基础版相同)
// 多列应用列表
List() {
ForEach(this.apps, (app:AppType) => {
ListItem() {
// 列表项内容(与基础版相同)
}
.width(this.getItemWidth()) // 根据列数设置宽度
.padding(8)
})
}
.width('100%')
.layoutWeight(1)
.lanes(this.getColumnCount()) // 根据屏幕宽度设置列数
.divider({ // 设置网格分割线
strokeWidth: 1,
color: '#E5E5E5',
startMargin: 8,
endMargin: 8
})
// 底部导航栏(与基础版相同)
}
// Column属性设置(与基础版相同)
}
}
在这个示例中:
- 添加了screenWidth状态变量,用于存储屏幕宽度
- 实现了getColumnCount方法,根据屏幕宽度计算列数
- 实现了getItemWidth方法,根据列数计算列表项宽度
- 在aboutToAppear生命周期函数中获取屏幕宽度
- 在List组件的lanes属性和ListItem的width属性中使用计算的值
3.2 列表项样式优化
我们可以优化列表项的样式,使其更加美观:
ListItem() {
Column() {
// 应用图标容器
Stack() {
// 应用图标
Image(app.icon)
.width(60)
.height(60)
.borderRadius(12)
// 下载量标签
Text(app.downloads)
.fontSize(10)
.fontColor('#FFFFFF')
.backgroundColor('rgba(0, 0, 0, 0.6)')
.borderRadius({ bottomLeft: 12, bottomRight: 12 })
.width(60)
.height(20)
.textAlign(TextAlign.Center)
.position({ x: 0, y: 40 })
}
.width(60)
.height(60)
// 应用名称
Text(app.name)
.width(100)
.fontSize(14)
.margin({ top: 8 })
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
// 安装按钮
Button('安装')
.width(80)
.height(28)
.fontSize(12)
.backgroundColor('#007DFF')
.margin({ top: 8 })
}
.alignItems(HorizontalAlign.Center)
.width('100%')
.padding(12)
.backgroundColor('#FFFFFF')
.borderRadius(8)
.shadow({
radius: 4,
color: 'rgba(0, 0, 0, 0.1)',
offsetX: 0,
offsetY: 2
})
}
在这个示例中:
- 使用Stack组件作为应用图标的容器,可以在图标上方叠加下载量标签
- 为下载量标签设置半透明背景和圆角,使其更加美观
- 添加了安装按钮,使列表项更加实用
- 为整个列表项添加了背景色、圆角和阴影效果,使其看起来像一个卡片
3.3 列表加载优化
在实际应用中,应用列表可能包含大量数据,我们可以实现分页加载功能,提高列表的加载性能:
@Component
export struct AdvancedMultiColumnList {
// 应用数据
private allApps: AppType[] = [...] // 所有应用数据
// 当前显示的应用数据
@State apps: AppType[] = []
// 每页加载的应用数量
private pageSize: number = 12
// 当前页码
@State currentPage: number = 1
// 是否正在加载
@State isLoading: boolean = false
// 是否还有更多数据
@State hasMore: boolean = true
// 加载下一页数据
private loadNextPage() {
if (this.isLoading || !this.hasMore) {
return
}
this.isLoading = true
// 模拟网络请求延迟
setTimeout(() => {
const start = (this.currentPage - 1) * this.pageSize
const end = this.currentPage * this.pageSize
const newApps = this.allApps.slice(start, end)
if (newApps.length > 0) {
this.apps = [...this.apps, ...newApps]
this.currentPage++
this.hasMore = end < this.allApps.length
} else {
this.hasMore = false
}
this.isLoading = false
}, 1000)
}
aboutToAppear() {
// 初始加载第一页数据
this.loadNextPage()
}
build() {
Column() {
// 标题栏和其他内容(与基础版相同)
// 多列应用列表
List() {
ForEach(this.apps, (app:AppType) => {
// 列表项内容(与基础版相同)
})
// 加载更多
if (this.hasMore || this.isLoading) {
ListItem() {
Column() {
if (this.isLoading) {
LoadingProgress()
.width(24)
.height(24)
Text('正在加载...')
.fontSize(14)
.fontColor('#999999')
.margin({ top: 8 })
} else {
Text('加载更多')
.fontSize(14)
.fontColor('#007DFF')
}
}
.width('100%')
.height(60)
.justifyContent(FlexAlign.Center)
.onClick(() => {
if (!this.isLoading) {
this.loadNextPage()
}
})
}
.width('100%')
}
}
.width('100%')
.layoutWeight(1)
.lanes(3) // 设置为3列布局
.divider({ // 设置网格分割线
strokeWidth: 1,
color: '#E5E5E5',
startMargin: 8,
endMargin: 8
})
.onReachEnd(() => {
// 滚动到底部时自动加载下一页
this.loadNextPage()
})
// 底部导航栏(与基础版相同)
}
// Column属性设置(与基础版相同)
}
}
在这个示例中:
- 将所有应用数据存储在allApps属性中,当前显示的应用数据存储在apps状态变量中
- 添加了pageSize、currentPage、isLoading和hasMore属性,用于控制分页加载
- 实现了loadNextPage方法,用于加载下一页数据
- 在aboutToAppear生命周期函数中初始加载第一页数据
- 在列表底部添加了加载更多的ListItem,显示加载状态或加载更多按钮
- 为List组件添加了onReachEnd事件处理函数,滚动到底部时自动加载下一页
总结
在本篇教程中,我们深入探讨了HarmonyOS NEXT的多列列表的进阶特性和用法。 通过这些进阶技巧,我们可以构建更加功能丰富、交互友好的应用推荐页。这些知识点不仅适用于应用推荐页,也可以应用到其他类型的多列列表界面设计中,如商品展示、图片库等。
00
- 0回答
- 4粉丝
- 0关注
相关话题
- 137.[HarmonyOS NEXT 实战案例七:List系列] 多列列表组件实战:打造精美应用推荐页 基础篇
- 136.[HarmonyOS NEXT 实战案例七:List系列] 水平列表组件实战:打造精美图片库 进阶篇
- 152.[HarmonyOS NEXT 实战案例十二:List系列] 卡片样式列表组件实战:打造精美电商应用 进阶篇
- 146.[HarmonyOS NEXT 实战案例七 :List系列] 可选择列表进阶篇
- 142.[HarmonyOS NEXT 实战案例九:List系列] 分组列表组件实战:打造分类设置菜单 进阶篇
- 134.[HarmonyOS NEXT 实战案例六:List系列] 垂直列表组件实战:打造高效联系人列表 进阶篇
- 135.[HarmonyOS NEXT 实战案例七:List系列] 水平列表组件实战:打造精美图片库 基础篇
- 144.[HarmonyOS NEXT 实战案例十:List系列] 字母索引列表组件实战:打造高效联系人应用 进阶篇
- 140.[HarmonyOS NEXT 实战案例八:List系列] 滑动操作列表组件实战:打造高效待办事项应用 进阶篇
- 151.[HarmonyOS NEXT 实战案例十二:List系列] 卡片样式列表组件实战:打造精美电商应用 基础篇
- 148.[HarmonyOS NEXT 实战案例八 :List系列] 粘性头部列表进阶篇
- 156.[HarmonyOS NEXT 实战案例十二 :List系列] 聊天消息列表 - 进阶篇
- 150.[HarmonyOS NEXT 实战案例十一:List系列] 下拉刷新和上拉加载更多列表组件实战:打造高效新闻应用 进阶篇
- 154.[HarmonyOS NEXT 实战案例十一 :List系列] 自定义内容列表 - 进阶篇
- [HarmonyOS NEXT 实战案例六:List系列] 垂直列表组件实战:打造高效联系人列表 基础篇