[HarmonyOS NEXT 实战案例十三] 音乐播放器网格布局(上)
[HarmonyOS NEXT 实战案例十三] 音乐播放器网格布局(上)
项目已开源,开源地址: https://gitcode.com/nutpi/HarmonyosNextCaseStudyTutorial , 欢迎fork & star
效果演示
1. 概述
本教程将详细讲解如何使用HarmonyOS NEXT的GridRow和GridCol组件实现一个音乐播放器的网格布局。音乐播放器是移动应用中常见的功能,通过网格布局可以实现清晰、美观的界面结构,提升用户体验。
本教程将涵盖以下内容:
- 音乐播放器的整体布局设计
- 专辑封面区域实现
- 歌曲信息区域实现
- 进度条区域实现
- 控制按钮区域实现
- GridRow和GridCol组件的灵活应用
2. 状态管理设计
在实现音乐播放器之前,我们首先定义几个状态变量来管理播放器的状态:
@State isPlaying: boolean = false // 是否正在播放
@State currentTime: number = 0 // 当前播放时间(秒)
@State duration: number = 180 // 歌曲总时长(秒,这里设为3分钟)
这些状态变量将用于控制播放/暂停按钮的显示状态,以及进度条的当前值和最大值。
3. 整体布局结构
音乐播放器的整体布局采用Column容器,内部包含四个主要部分,每个部分都使用GridRow和GridCol组件进行布局:
build() {
Column() {
// 专辑封面
GridRow({ columns: 1 }) {
// ...
}
// 歌曲信息
GridRow({ columns: 1 }) {
// ...
}
// 进度条
GridRow({ columns: 1 }) {
// ...
}
// 控制按钮
GridRow({ columns: 5 }) {
// ...
}
}
.width('100%')
.height('100%')
}
这种结构将播放器界面分为四个垂直排列的部分,每个部分内部又使用GridRow和GridCol进行更细致的布局。
4. 专辑封面区域实现
专辑封面区域使用一个单列的GridRow,内部包含一个GridCol,用于居中显示专辑封面图片:
// 专辑封面
GridRow({ columns: 1 }) {
GridCol({ span: 1 }) {
Image($r("app.media.big14"))
.width(200)
.height(200)
.borderRadius(100)
.margin({ top: 32, bottom: 32 })
}
}
在这个部分:
- GridRow设置为单列布局(
columns: 1
),使内容在水平方向上居中 - GridCol占据整个行宽(
span: 1
) - Image组件显示专辑封面,设置宽高为200像素,边框圆角为100像素(使其呈现为圆形),上下边距为32像素
5. 歌曲信息区域实现
歌曲信息区域同样使用单列的GridRow,显示歌曲名称和歌手信息:
// 歌曲信息
GridRow({ columns: 1 }) {
GridCol({ span: 1 }) {
Column() {
Text('夜曲')
.fontSize(24)
.fontWeight(FontWeight.Bold)
Text('周杰伦')
.fontSize(16)
.fontColor('#9E9E9E')
.margin({ top: 8 })
}
}
}
在这个部分:
- GridRow和GridCol的配置与专辑封面区域相同
- 内部使用Column容器垂直排列两个Text组件
- 第一个Text显示歌曲名称,使用较大的粗体字体
- 第二个Text显示歌手名称,使用较小的灰色字体,顶部边距为8像素
6. 进度条区域实现
进度条区域使用单列的GridRow,内部包含播放时间、进度条和总时长:
// 进度条
GridRow({ columns: 1 }) {
GridCol({ span: 1 }) {
Row() {
Text(this.formatTime(this.currentTime))
.fontSize(12)
.fontColor('#9E9E9E')
Slider({
value: this.currentTime,
min: 0,
max: this.duration,
step: 1,
style: SliderStyle.OutSet
})
.width('70%')
.onChange((value) => {
this.currentTime = value
})
.margin({ left: 8, right: 8 })
Text(this.formatTime(this.duration))
.fontSize(12)
.fontColor('#9E9E9E')
}
.width('100%')
.margin({ top: 24, bottom: 24 })
}
}
在这个部分:
- GridRow和GridCol的配置与前两个区域相同
- 内部使用Row容器水平排列三个组件
- 左侧Text显示当前播放时间,使用formatTime方法格式化时间
- 中间Slider组件作为进度条,宽度为70%,最小值为0,最大值为歌曲总时长
- 右侧Text显示歌曲总时长
- 整个Row设置上下边距为24像素
7. 控制按钮区域实现
控制按钮区域使用五列的GridRow,每个按钮占据一列:
// 控制按钮
GridRow({ columns: 5 }) {
GridCol({ span: 1 }) {
Image($r('app.media.01'))
.width(24)
.height(24)
}
GridCol({ span: 1 }) {
Image($r('app.media.02'))
.width(24)
.height(24)
}
GridCol({ span: 1 }) {
Image(this.isPlaying ? $r('app.media.03') : $r('app.media.01'))
.width(32)
.height(32)
.onClick(() => {
this.isPlaying = !this.isPlaying
})
}
GridCol({ span: 1 }) {
Image($r('app.media.04'))
.width(24)
.height(24)
}
GridCol({ span: 1 }) {
Image($r('app.media.05'))
.width(24)
.height(24)
}
}
.margin({ top: 16, bottom: 32 })
在这个部分:
- GridRow设置为五列布局(
columns: 5
),使五个控制按钮均匀分布 - 每个GridCol占据一列(
span: 1
) - 每个GridCol内部包含一个Image组件,显示不同的控制图标
- 中间的播放/暂停按钮稍大(32x32像素),其他按钮较小(24x24像素)
- 播放/暂停按钮根据isPlaying状态显示不同的图标,并添加点击事件处理
- 整个GridRow设置上边距为16像素,下边距为32像素
8. 辅助方法实现
为了格式化时间显示,我们实现了一个辅助方法:
private formatTime(seconds: number): string {
const mins = Math.floor(seconds / 60)
const secs = seconds % 60
return `${mins}:${secs < 10 ? '0' + secs : secs}`
}
这个方法将秒数转换为"分:秒"格式,并确保秒数小于10时前面添加0,如"3:05"。
9. GridRow和GridCol配置详解
在本案例中,我们使用了不同配置的GridRow和GridCol组件:
9.1 单列布局
对于专辑封面、歌曲信息和进度条区域,我们使用了单列布局:
GridRow({ columns: 1 }) {
GridCol({ span: 1 }) {
// 内容
}
}
这种配置使内容在水平方向上居中,占据整个可用宽度。
9.2 多列布局
对于控制按钮区域,我们使用了五列布局:
GridRow({ columns: 5 }) {
// 五个GridCol,每个span: 1
}
这种配置使五个按钮均匀分布在一行中,每个按钮占据总宽度的1/5。
10. 完整代码
下面是音乐播放器网格布局的完整代码:
// 音乐播放器网格布局
@Component
export struct MusicPlayerGrid {
@State isPlaying: boolean = false
@State currentTime: number = 0
@State duration: number = 180 // 3分钟
build() {
Column() {
// 专辑封面
GridRow({ columns: 1 }) {
GridCol({ span: 1 }) {
Image($r("app.media.big14"))
.width(200)
.height(200)
.borderRadius(100)
.margin({ top: 32, bottom: 32 })
}
}
// 歌曲信息
GridRow({ columns: 1 }) {
GridCol({ span: 1 }) {
Column() {
Text('夜曲')
.fontSize(24)
.fontWeight(FontWeight.Bold)
Text('周杰伦')
.fontSize(16)
.fontColor('#9E9E9E')
.margin({ top: 8 })
}
}
}
// 进度条
GridRow({ columns: 1 }) {
GridCol({ span: 1 }) {
Row() {
Text(this.formatTime(this.currentTime))
.fontSize(12)
.fontColor('#9E9E9E')
Slider({
value: this.currentTime,
min: 0,
max: this.duration,
step: 1,
style: SliderStyle.OutSet
})
.width('70%')
.onChange((value) => {
this.currentTime = value
})
.margin({ left: 8, right: 8 })
Text(this.formatTime(this.duration))
.fontSize(12)
.fontColor('#9E9E9E')
}
.width('100%')
.margin({ top: 24, bottom: 24 })
}
}
// 控制按钮
GridRow({ columns: 5 }) {
GridCol({ span: 1 }) {
Image($r('app.media.01'))
.width(24)
.height(24)
}
GridCol({ span: 1 }) {
Image($r('app.media.02'))
.width(24)
.height(24)
}
GridCol({ span: 1 }) {
Image(this.isPlaying ? $r('app.media.03') : $r('app.media.01'))
.width(32)
.height(32)
.onClick(() => {
this.isPlaying = !this.isPlaying
})
}
GridCol({ span: 1 }) {
Image($r('app.media.04'))
.width(24)
.height(24)
}
GridCol({ span: 1 }) {
Image($r('app.media.05'))
.width(24)
.height(24)
}
}
.margin({ top: 16, bottom: 32 })
}
.width('100%')
.height('100%')
}
private formatTime(seconds: number): string {
const mins = Math.floor(seconds / 60)
const secs = seconds % 60
return `${mins}:${secs < 10 ? '0' + secs : secs}`
}
}
11. GridRow和GridCol组件详解
11.1 GridRow组件
GridRow是HarmonyOS NEXT提供的网格行容器组件,用于创建网格布局。它具有以下主要属性:
属性 | 类型 | 描述 |
---|---|---|
columns | number | { xs?: number, sm?: number, md?: number, lg?: number, xl?: number, xxl?: number } | 设置布局列数 |
gutter | number | { x?: number, y?: number } | 栅格间隔 |
breakpoints | { value: string[], reference: BreakpointsReference } | 设置断点值的断点数列以及基于窗口或容器尺寸的相应参照 |
direction | GridRowDirection | 栅格布局排列方向 |
11.2 GridCol组件
GridCol是HarmonyOS NEXT提供的网格列容器组件,用于在GridRow中创建网格列。它具有以下主要属性:
属性 | 类型 | 描述 |
---|---|---|
span | number | { xs?: number, sm?: number, md?: number, lg?: number, xl?: number, xxl?: number } | 列宽度 |
offset | number | { xs?: number, sm?: number, md?: number, lg?: number, xl?: number, xxl?: number } | 列偏移量 |
order | number | { xs?: number, sm?: number, md?: number, lg?: number, xl?: number, xxl?: number } | 列顺序 |
12. 布局效果分析
本案例中的音乐播放器布局具有以下特点:
- 垂直分区明确:整体布局分为四个垂直区域(专辑封面、歌曲信息、进度条、控制按钮),结构清晰
- 水平对齐一致:专辑封面、歌曲信息和进度条区域都采用单列布局,保持水平居中对齐
- 控制按钮均匀分布:控制按钮区域采用五列布局,使五个按钮均匀分布,视觉平衡
- 层次感强:通过不同的字体大小、颜色和间距,创造出良好的视觉层次
- 交互元素明确:播放/暂停按钮和进度条作为主要交互元素,尺寸较大且位置突出
这种布局设计使音乐播放器界面既美观又实用,用户可以轻松地查看歌曲信息、控制播放进度和操作播放控制。
13. 总结
本教程详细讲解了如何使用HarmonyOS NEXT的GridRow和GridCol组件实现音乐播放器的网格布局。通过合理的状态管理和布局设计,我们创建了一个功能完整、界面美观的音乐播放器界面。
主要内容包括:
- 音乐播放器的状态管理设计
- 整体布局结构的实现
- 专辑封面、歌曲信息、进度条和控制按钮区域的详细实现
- GridRow和GridCol组件的不同配置方式
- 时间格式化辅助方法的实现
通过本教程,你应该已经掌握了如何使用GridRow和GridCol组件实现复杂的界面布局,以及如何管理组件状态和处理用户交互。这些技能可以应用到各种需要网格布局的场景中,如媒体播放器、照片浏览器、控制面板等。
在下一篇教程中,我们将进一步探讨如何优化音乐播放器,添加更多功能和交互效果,使其更加实用和吸引人。
- 0回答
- 3粉丝
- 0关注
- [HarmonyOS NEXT 实战案例十三] 音乐播放器网格布局(下)
- [HarmonyOS NEXT 实战案例:音乐播放器] 基础篇 - 水平分割布局打造音乐播放器界面
- [HarmonyOS NEXT 实战案例:音乐播放器] 进阶篇 - 交互式音乐播放器的状态管理与控制
- HarmonyOS NEXT 应用开发实战:音乐播放器的完整实现
- [HarmonyOS NEXT 实战案例四] 天气应用网格布局(上)
- [HarmonyOS NEXT 实战案例六] 餐饮菜单网格布局(上)
- [HarmonyOS NEXT 实战案例七] 健身课程网格布局(上)
- [HarmonyOS NEXT 实战案例九] 旅游景点网格布局(上)
- [HarmonyOS NEXT 实战案例十四] 任务管理看板网格布局(上)
- [HarmonyOS NEXT 实战案例十] 电子书网格布局(上)
- [HarmonyOS NEXT 实战案例十八] 日历日程视图网格布局(上)
- [HarmonyOS NEXT 实战案例十七] 设置选项列表网格布局(上)
- [HarmonyOS NEXT 实战案例三] 音乐专辑网格展示(上)
- [HarmonyOS NEXT 实战案例五] 社交应用照片墙网格布局(上)
- [HarmonyOS NEXT 实战案例一] 电商首页商品网格布局(上)