147.[HarmonyOS NEXT 实战案例八 :List系列] 粘性头部列表基础篇
[HarmonyOS NEXT 实战案例八 :List系列] 粘性头部列表基础篇
项目已开源,开源地址: https://gitcode.com/nutpi/HarmonyosNextCaseStudyTutorial , 欢迎fork & star
效果演示
粘性头部列表是移动应用中常见的UI模式,它允许列表的分组标题在滚动时保持可见,提供更好的导航体验。本教程将详细讲解如何在HarmonyOS NEXT中实现一个功能完善的粘性头部列表,以音乐播放器应用为例,展示如何创建按专辑分组的音乐列表。
一、粘性头部列表概述
粘性头部列表是List组件与ListItemGroup组件结合使用的一种应用场景,它具有以下特点:
- 分组显示:内容按照一定规则分组显示
- 粘性头部:当滚动时,当前分组的头部会固定在屏幕顶部
- 层级结构:通过视觉设计清晰地表达内容的层级关系
- 导航便捷:用户可以快速了解当前浏览的内容类别
在HarmonyOS NEXT中,粘性头部列表主要通过以下组件实现:
- List:基础列表容器
- ListItemGroup:列表项分组容器
- ListItem:列表项
- sticky属性:控制粘性效果
二、数据模型设计
首先,我们需要定义音乐数据的接口:
// 歌曲接口
interface SongsType {
title: string,
duration: string,
isLiked: boolean
}
// 专辑接口
interface MusicType {
album: string,
artist: string,
cover: Resource,
year: string,
songs: SongsType[]
}
// 当前播放歌曲接口
interface CurrentSongType {
album: string,
title: string
}
这些接口定义了我们的数据结构:
SongsType
:定义歌曲的基本属性(标题、时长、是否喜欢)MusicType
:定义专辑的基本属性(专辑名、艺术家、封面、年份、歌曲列表)CurrentSongType
:定义当前播放歌曲的信息(所属专辑、歌曲标题)
然后,我们创建示例音乐数据:
private musicData: MusicType[] = [
{
album: '星辰大海',
artist: '周杰伦',
cover: $r('app.media.big25'),
year: '2023',
songs: [
{ title: '星辰大海', duration: '4:25', isLiked: true },
{ title: '城市之光', duration: '3:48', isLiked: false },
// 更多歌曲...
]
},
// 更多专辑...
]
三、状态管理
为了管理当前播放的歌曲状态,我们定义以下状态变量:
// 当前播放歌曲
@State currentSong: CurrentSongType | null = null
这个状态变量用于跟踪当前正在播放的歌曲,初始值为null表示没有歌曲在播放。
四、核心功能实现
1. 播放歌曲功能
// 播放歌曲
playSong(album: string, title: string) {
this.currentSong = { album, title }
}
这个方法用于设置当前播放的歌曲,接收专辑名和歌曲标题作为参数。
2. 专辑头部构建器
// 构建专辑头部
@Builder
AlbumHeader(album: string, artist: string, cover: Resource, year: string) {
Row() {
// 专辑封面
Image(cover)
.width(60)
.height(60)
.borderRadius(8)
.margin({ right: 16 })
// 专辑信息
Column() {
Text(album)
.fontSize(18)
.fontWeight(FontWeight.Bold)
Text(artist)
.fontSize(16)
.fontColor('#666666')
.margin({ top: 4 })
Text(year)
.fontSize(14)
.fontColor('#999999')
.margin({ top: 2 })
}
.alignItems(HorizontalAlign.Start)
}
.width('100%')
.backgroundColor('#FFFFFF')
.padding({ left: 16, right: 16, top: 12, bottom: 12 })
}
这个Builder用于构建专辑头部的UI,包括专辑封面和专辑信息(专辑名、艺术家、年份)。
五、UI构建
1. 整体布局
build() {
Stack({ alignContent: Alignment.Bottom }) {
Column() {
// 标题栏
Row() { /* ... */ }
// 音乐列表
List() { /* ... */ }
}
.width('100%')
.height('100%')
.backgroundColor('#FFFFFF')
// 底部播放控制栏(当有歌曲播放时显示)
if (this.currentSong) {
Row() { /* ... */ }
}
}
.width('100%')
.height('100%')
}
整体布局使用Stack容器,包含两个主要部分:
- 主内容区(Column容器):包含标题栏和音乐列表
- 底部播放控制栏:仅在有歌曲播放时显示
2. 标题栏实现
// 标题栏
Row() {
Text('音乐')
.fontSize(24)
.fontWeight(FontWeight.Bold)
Blank()
Image($r('app.media.music_icon'))
.width(24)
.height(24)
.margin({ right: 16 })
}
.width('100%')
.height(56)
.padding({ left: 16, right: 16 })
.backgroundColor('#F1F3F5')
标题栏包含应用标题和一个音乐图标。
3. 音乐列表实现
// 音乐列表
List() {
ForEach(this.musicData, (albumData: MusicType) => {
ListItemGroup({
header: this.AlbumHeader(albumData.album, albumData.artist, albumData.cover, albumData.year),
space: 0
}) {
ForEach(albumData.songs, (song: SongsType) => {
ListItem() {
Row() {
// 歌曲信息
Column() {
Text(song.title)
.fontSize(16)
.fontWeight(FontWeight.Medium)
Text(song.duration)
.fontSize(14)
.fontColor('#666666')
.margin({ top: 4 })
}
.alignItems(HorizontalAlign.Start)
.layoutWeight(1)
// 喜欢按钮
Image(song.isLiked ? $r('app.media.heart_filled') : $r('app.media.heart_outline'))
.width(24)
.height(24)
.margin({ right: 16 })
// 更多按钮
Image($r('app.media.dcc_health_icon'))
.width(24)
.height(24)
}
.width('100%')
.padding({ left: 16, right: 16, top: 12, bottom: 12 })
.onClick(() => this.playSong(albumData.album, song.title))
.backgroundColor(
this.currentSong?.album === albumData.album &&
this.currentSong?.title === song.title ?
'#F0F7FF' : '#FFFFFF'
)
}
.height(64)
})
}
})
}
.sticky(StickyStyle.Header) // 设置粘性头部
.width('100%')
.layoutWeight(1)
.divider({ // 设置分割线
strokeWidth: 1,
color: '#E5E5E5',
startMargin: 16,
endMargin: 16
})
音乐列表的关键点:
- 使用
ForEach
遍历专辑数据,为每个专辑创建一个ListItemGroup
- 使用自定义的
AlbumHeader
构建器作为ListItemGroup
的头部 - 在每个
ListItemGroup
中,再次使用ForEach
遍历歌曲数据,为每首歌曲创建一个ListItem
- 为
List
组件设置sticky(StickyStyle.Header)
属性,启用粘性头部功能 - 为歌曲项添加点击事件,点击时调用
playSong
方法 - 根据当前播放歌曲状态,设置不同的背景色以提供视觉反馈
4. 底部播放控制栏实现
// 底部播放控制栏(当有歌曲播放时显示)
if (this.currentSong) {
Row() {
// 当前播放歌曲信息
Column() {
Text(this.currentSong.title)
.fontSize(16)
.fontWeight(FontWeight.Medium)
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
Text(this.currentSong.album)
.fontSize(14)
.fontColor('#666666')
.margin({ top: 2 })
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
}
.alignItems(HorizontalAlign.Start)
.layoutWeight(1)
// 播放控制按钮
Row({ space: 16 }) {
Image($r('app.media.active_weather_icon'))
.width(24)
.height(24)
Image($r('app.media.mobile_calculator_ap'))
.width(32)
.height(32)
Image($r('app.media.note_icon'))
.width(24)
.height(24)
}
}
.width('100%')
.height(72)
.padding({ left: 16, right: 16 })
.backgroundColor('#FFFFFF')
.borderColor('#E5E5E5')
.borderWidth({ top: 1 })
}
底部播放控制栏仅在有歌曲播放时显示,包含当前播放歌曲信息和播放控制按钮。
六、关键技术点分析
1. 粘性头部的实现
粘性头部功能主要通过List
组件的sticky
属性实现:
.sticky(StickyStyle.Header) // 设置粘性头部
这个属性使得ListItemGroup
的头部在滚动时保持可见,直到下一个分组的头部出现。
2. ListItemGroup的使用
ListItemGroup
组件用于创建分组列表,它接收一个header
参数作为分组的头部:
ListItemGroup({
header: this.AlbumHeader(albumData.album, albumData.artist, albumData.cover, albumData.year),
space: 0
})
header
参数可以是一个自定义的Builder,这里我们使用AlbumHeader
构建器来创建专辑头部。
3. 条件渲染
我们使用条件渲染来控制底部播放控制栏的显示:
if (this.currentSong) {
Row() { /* ... */ }
}
只有当currentSong
不为null时,才会显示底部播放控制栏。
4. 状态反馈
为了提供良好的用户体验,我们为当前播放的歌曲提供视觉反馈:
.backgroundColor(
this.currentSong?.album === albumData.album &&
this.currentSong?.title === song.title ?
'#F0F7FF' : '#FFFFFF'
)
当歌曲正在播放时,其背景色会变为浅蓝色,以便用户快速识别当前播放的歌曲。
七、代码结构与样式设置
组件部分 | 主要功能 | 样式设置 |
---|---|---|
Stack | 整体容器 | 宽高100%,底部对齐 |
Column | 主内容区 | 宽高100%,白色背景 |
标题栏Row | 显示应用标题和图标 | 高56px,左右内边距16px,浅灰背景 |
List | 显示音乐列表 | 宽100%,弹性布局权重1,粘性头部,带分割线 |
ListItemGroup | 专辑分组 | 自定义头部,间距0 |
ListItem | 单首歌曲 | 高64px,点击事件,条件背景色 |
底部Row | 播放控制栏 | 高72px,左右内边距16px,白色背景,顶部边框 |
八、粘性头部列表的应用场景
粘性头部列表适用于多种应用场景,包括但不限于:
- 音乐播放器:按专辑、艺术家或流派分组显示歌曲
- 联系人列表:按字母或组织分组显示联系人
- 设置页面:按功能类别分组显示设置项
- 电商应用:按类别分组显示商品
- 日历应用:按月份或周分组显示事件
- 新闻应用:按日期或主题分组显示新闻
九、总结
本教程详细讲解了如何在HarmonyOS NEXT中实现一个功能完善的粘性头部列表, 通过本教程,你应该能够掌握HarmonyOS NEXT中粘性头部列表的基本实现方法,并能够应用到自己的项目中。在进阶篇中,我们将探讨如何增强粘性头部列表的功能,如自定义粘性效果、动画过渡、交互优化等高级特性。
- 0回答
- 4粉丝
- 0关注
- 148.[HarmonyOS NEXT 实战案例八 :List系列] 粘性头部列表进阶篇
- 155.[HarmonyOS NEXT 实战案例十二 :List系列] 聊天消息列表 - 基础篇
- 139.[HarmonyOS NEXT 实战案例八:List系列] 滑动操作列表组件实战:打造高效待办事项应用 基础篇
- 145.[HarmonyOS NEXT 实战案例七 :List系列] 可选择列表基础篇
- [HarmonyOS NEXT 实战案例六:List系列] 垂直列表组件实战:打造高效联系人列表 基础篇
- 153.[HarmonyOS NEXT 实战案例十一 :List系列] 自定义内容列表 - 基础篇
- 141.[HarmonyOS NEXT 实战案例九:List系列] 分组列表组件实战:打造分类设置菜单 基础篇
- 140.[HarmonyOS NEXT 实战案例八:List系列] 滑动操作列表组件实战:打造高效待办事项应用 进阶篇
- 137.[HarmonyOS NEXT 实战案例七:List系列] 多列列表组件实战:打造精美应用推荐页 基础篇
- 151.[HarmonyOS NEXT 实战案例十二:List系列] 卡片样式列表组件实战:打造精美电商应用 基础篇
- 156.[HarmonyOS NEXT 实战案例十二 :List系列] 聊天消息列表 - 进阶篇
- 143.[HarmonyOS NEXT 实战案例十:List系列] 字母索引列表组件实战:打造高效联系人应用 基础篇
- 135.[HarmonyOS NEXT 实战案例七:List系列] 水平列表组件实战:打造精美图片库 基础篇
- 146.[HarmonyOS NEXT 实战案例七 :List系列] 可选择列表进阶篇
- 154.[HarmonyOS NEXT 实战案例十一 :List系列] 自定义内容列表 - 进阶篇