目录
1.用户随意控制播放进度
2.歌曲暂停和播放控制和歌曲上一首、下一首播放控制
3.歌曲列表
4.歌曲列表数据动态化和背景雾化
5.唱针效果
6.结语
1.用户随意控制播放进度
src/main/ets/services/AvPlayerManager.ets:
// 让播放对象从某个时间点开始播放
static async seek(time:number) {
AvPlayerManager.avPlayer.seek(time)
}
src/main/ets/pages/playPage.ets:
import { AvPlayerManager, songItemType } from '../services/AvPlayerManager'
@Entry
@Component
struct PlayPage {
@State angle: number = 0 // 控制角度变化值 0 - 360度改变
@State totalTime: number = 0
@State currentTime: number = 0
aboutToAppear() {
this.totalTime = AvPlayerManager.avPlayer.duration // 表示当前正在播放歌曲的总时间,单位是毫秒
// 不停的获取当前歌曲的已播放时长
AvPlayerManager.avPlayer.on('timeUpdate', (time) => {
// time表示当前歌曲已经播放的时长,单位是毫秒
this.currentTime = time
})
}
// 作用:接收一个毫秒数值,转成成 00:00这种格式的字符串返回
formatTime(time: number) {
// 1. 计算出分钟数
let seconds = time / 1000 //将毫秒数转成总秒数
let min = Math.floor(seconds / 60) // 获取到了分钟部分
// 2. 计算出除开分钟之外的剩余的秒数
let s = Math.ceil(seconds % 60) // Math.ceil(19.89) -> 20
return `${min.toString().padStart(2,'0')}:${s.toString().padStart(2,'0')}`
}
build() {
Column() {
// CD唱片
Stack() {
Image($r('app.media.ic_cd'))
.height(300)
.borderRadius(300)
Image(AvPlayerManager.songs[AvPlayerManager.index].img)
.height(200)
.borderRadius(200)
}
// 控制一个元素旋转 (这个属性一定要写在animation前面,否则不会触发动画)
.rotate({ angle: this.angle })
// 元素加载完毕之后触发一个回调函数 .onAppear
.onAppear(() => {
this.angle = 360 //将角度改成360都
})
// 增加旋转的动画效果
.animation({
duration: 10000, // 用10秒钟的时间让元素旋转一圈
curve: Curve.Linear, // 匀速旋转
iterations: -1 //表示设置旋转的圈数,如果是-1则表示不停的转,如果是正数则表示转的圈数
})
// 歌曲信息
Column({ space: 5 }) {
Text(AvPlayerManager.songs[AvPlayerManager.index].name)
.fontSize(25)
.fontWeight(800)
.fontColor(Color.White)
Text(AvPlayerManager.songs[AvPlayerManager.index].author)
.fontSize(15)
.fontColor(Color.White)
}
.width('100%')
// 播放进度+控制按钮容器
Column() {
// 播放进度
Row({ space: 5 }) {
Text(this.formatTime(this.currentTime)) // 当前进度时间
.fontColor(Color.White)
Slider({
min: 0,
max: this.totalTime,
value: this.currentTime
})
.onChange((time)=>{
AvPlayerManager.seek(time)
})
.layoutWeight(1)
Text(this.formatTime(this.totalTime)) //歌曲总时间
.fontColor(Color.White)
}
.padding({ left: 10, right: 10, bottom: 20 })
// 控制按钮
Row() {
Image($r('app.media.ic_repeat'))
.width(30)
Image($r('app.media.ic_prev'))
.width(30)
.fillColor(Color.White)
Image($r('app.media.ic_play'))
.width(45)
.fillColor(Color.White)
Image($r('app.media.ic_next'))
.width(30)
.fillColor(Color.White)
Image($r('app.media.ic_song_list'))
.fillColor(Color.White)
.width(30)
}
.width('100%')
.justifyContent(FlexAlign.SpaceAround)
.margin({ bottom: -30 })
}
.width('100%')
.justifyContent(FlexAlign.SpaceAround)
}
.justifyContent(FlexAlign.SpaceAround)
.height('100%')
.width('100%')
// 线性渐变
.linearGradient({
angle: 180, // 颜色从上往下变化
colors: [ // 渐变颜色数组
['#7f797a', 0.1], //灰色
['#b43038', 0.5], // 红色
['#b43038', 0.8], // 红色
['#b43038', 1], // 红色
]
})
}
}
关键是
.onChange((time)=>{
AvPlayerManager.seek(time)
})
该方法能够跳转到AvPlayerManager的任意时间点。
2.歌曲暂停和播放控制和歌曲上一首、下一首播放控制
src/main/ets/pages/playPage.ets:
import { AvPlayerManager, songItemType } from '../services/AvPlayerManager'
import emitter from '@ohos.events.emitter'
@Entry
@Component
struct PlayPage {
@State angle: number = 0 // 控制角度变化值 0 - 360度改变
@State totalTime: number = 0
@State currentTime: number = 0
@State isplaying: boolean = true
@State currentMusic: songItemType = Object()
aboutToAppear() {
// 当页面进入的时候,将当前播放歌曲的数据赋值给全局变量currentMusci
this.currentMusic = AvPlayerManager.songs[AvPlayerManager.index]
// 注册emiiter接收上一首,下一首歌曲播放的时候新传入的歌曲对象
emitter.on({ eventId: 0 }, (res) => {
this.currentMusic = JSON.parse(res.data['item'])
})
this.totalTime = AvPlayerManager.avPlayer.duration // 表示当前正在播放歌曲的总时间,单位是毫秒
// 不停的获取当前歌曲的已播放时长
AvPlayerManager.avPlayer.on('timeUpdate', (time) => {
// time表示当前歌曲已经播放的时长,单位是毫秒
this.currentTime = time
})
}
// 作用:接收一个毫秒数值,转成成 00:00这种格式的字符串返回
formatTime(time: number) {
// 1. 计算出分钟数
let seconds = time / 1000 //将毫秒数转成总秒数
let min = Math.floor(seconds / 60) // 获取到了分钟部分
// 2. 计算出除开分钟之外的剩余的秒数
let s = Math.ceil(seconds % 60) // Math.ceil(19.89) -> 20
return `${min.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`
}
build() {
Column() {
// CD唱片
Stack() {
Image($r('app.media.ic_cd'))
.height(300)
.borderRadius(300)
Image(this.currentMusic.img)
.height(200)
.borderRadius(200)
}
// 控制一个元素旋转 (这个属性一定要写在animation前面,否则不会触发动画)
.rotate({ angle: this.angle })
// 元素加载完毕之后触发一个回调函数 .onAppear
.onAppear(() => {
this.angle = 360 //将角度改成360都
})
// 增加旋转的动画效果
.animation({
duration: 10000, // 用10秒钟的时间让元素旋转一圈
curve: Curve.Linear, // 匀速旋转
iterations: -1 //表示设置旋转的圈数,如果是-1则表示不停的转,如果是正数则表示转的圈数
})
// 歌曲信息
Column({ space: 5 }) {
Text(this.currentMusic.name)
.fontSize(25)
.fontWeight(800)
.fontColor(Color.White)
Text(this.currentMusic.author)
.fontSize(15)
.fontColor(Color.White)
}
.width('100%')
// 播放进度+控制按钮容器
Column() {
// 播放进度
Row({ space: 5 }) {
Text(this.formatTime(this.currentTime)) // 当前进度时间
.fontColor(Color.White)
Slider({
min: 0,
max: this.totalTime,
value: this.currentTime
})
.onChange((time) => {
AvPlayerManager.seek(time)
})
.layoutWeight(1)
Text(this.formatTime(this.totalTime)) //歌曲总时间
.fontColor(Color.White)
}
.padding({ left: 10, right: 10, bottom: 20 })
// 控制按钮
Row() {
Image($r('app.media.ic_repeat'))
.width(30)
Image($r('app.media.ic_prev'))
.width(30)
.fillColor(Color.White)
.onClick(() => {
AvPlayerManager.pre()
})
Image(this.isplaying ? $r('app.media.ic_paused') : $r('app.media.ic_play'))
.width(45)
.fillColor(Color.White)
.onClick(() => {
if (this.isplaying == true) {
// 暂停歌曲
AvPlayerManager.pause()
this.isplaying = false
} else {
// 播放歌曲
AvPlayerManager.reWork()
this.isplaying = true
}
})
Image($r('app.media.ic_next'))
.width(30)
.fillColor(Color.White)
.onClick(() => {
AvPlayerManager.next()
})
Image($r('app.media.ic_song_list'))
.fillColor(Color.White)
.width(30)
}
.width('100%')
.justifyContent(FlexAlign.SpaceAround)
.margin({ bottom: -30 })
}
.width('100%')
.justifyContent(FlexAlign.SpaceAround)
}
.justifyContent(FlexAlign.SpaceAround)
.height('100%')
.width('100%')
// 线性渐变
.linearGradient({
angle: 180, // 颜色从上往下变化
colors: [ // 渐变颜色数组
['#7f797a', 0.1], //灰色
['#b43038', 0.5], // 红色
['#b43038', 0.8], // 红色
['#b43038', 1], // 红色
]
})
}
}
主要实现:
@State currentMusic: songItemType = Object()
aboutToAppear() {
// 当页面进入的时候,将当前播放歌曲的数据赋值给全局变量currentMusci
this.currentMusic = AvPlayerManager.songs[AvPlayerManager.index]
// 注册emiiter接收上一首,下一首歌曲播放的时候新传入的歌曲对象
emitter.on({ eventId: 0 }, (res) => {
this.currentMusic = JSON.parse(res.data['item'])
})
emitter.on能够接收AvPlayerManager发来的歌曲信息。
Image(this.currentMusic.img)
Text(this.currentMusic.name)
Text(this.currentMusic.author)
常量改为变量。
Image($r('app.media.ic_prev'))
.width(30)
.fillColor(Color.White)
.onClick(() => {
AvPlayerManager.pre()
})
在上一首按钮增加onclick属性,调用 AvPlayerManager.pre(),实现上一首跳转。
Image($r('app.media.ic_next'))
.width(30)
.fillColor(Color.White)
.onClick(() => {
AvPlayerManager.next()
})
同样,下一首图片增加onclick属性,调用 AvPlayerManager.next(),实现下一首跳转。
3.歌曲列表
点击PlayPage页面的三角箭头,能够显示出被折叠的歌曲。
src/main/ets/pages/playPage.ets:
import { AvPlayerManager, songItemType } from '../services/AvPlayerManager'
import emitter from '@ohos.events.emitter'
@Entry
@Component
struct PlayPage {
@State angle: number = 0 // 控制角度变化值 0 - 360度改变
@State totalTime: number = 0
@State currentTime: number = 0
@State isplaying: boolean = true
@State currentMusic: songItemType = Object()
@State h:number = 0 //控制底部歌曲列表容器的高度
aboutToAppear() {
// 当页面进入的时候,将当前播放歌曲的数据赋值给全局变量currentMusci
this.currentMusic = AvPlayerManager.songs[AvPlayerManager.index]
// 注册emiiter接收上一首,下一首歌曲播放的时候新传入的歌曲对象
emitter.on({ eventId: 0 }, (res) => {
this.currentMusic = JSON.parse(res.data['item'])
})
// 不停的获取当前歌曲的已播放时长
AvPlayerManager.avPlayer.on('timeUpdate', (time) => {
if (AvPlayerManager.avPlayer.state == 'playing') {
this.isplaying = true
} else {
this.isplaying = false
}
// time表示当前歌曲已经播放的时长,单位是毫秒
this.currentTime = time
// 放到这里能够解决切歌时候不能获取最新歌曲的总时长问题
this.totalTime = AvPlayerManager.avPlayer.duration // 表示当前正在播放歌曲的总时间,单位是毫秒
})
}
// 作用:接收一个毫秒数值,转成成 00:00这种格式的字符串返回
formatTime(time: number) {
// 1. 计算出分钟数
let seconds = time / 1000 //将毫秒数转成总秒数
let min = Math.floor(seconds / 60) // 获取到了分钟部分
// 2. 计算出除开分钟之外的剩余的秒数
let s = Math.ceil(seconds % 60) // Math.ceil(19.89) -> 20
return `${min.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`
}
build() {
Stack({alignContent:Alignment.Bottom}) {
Column() {
// CD唱片
Stack() {
Image($r('app.media.ic_cd'))
.height(300)
.borderRadius(300)
Image(this.currentMusic.img)
.height(200)
.borderRadius(200)
}
// 控制一个元素旋转 (这个属性一定要写在animation前面,否则不会触发动画)
.rotate({ angle: this.angle })
// 元素加载完毕之后触发一个回调函数 .onAppear
.onAppear(() => {
this.angle = 360 //将角度改成360都
})
// 增加旋转的动画效果
.animation({
duration: 10000, // 用10秒钟的时间让元素旋转一圈
curve: Curve.Linear, // 匀速旋转
iterations: -1 //表示设置旋转的圈数,如果是-1则表示不停的转,如果是正数则表示转的圈数
})
// 歌曲信息
Column({ space: 5 }) {
Text(this.currentMusic.name)
.fontSize(25)
.fontWeight(800)
.fontColor(Color.White)
Text(this.currentMusic.author)
.fontSize(15)
.fontColor(Color.White)
}
.width('100%')
// 播放进度+控制按钮容器
Column() {
// 播放进度
Row({ space: 5 }) {
Text(this.formatTime(this.currentTime)) // 当前进度时间
.fontColor(Color.White)
Slider({
min: 0,
max: this.totalTime,
value: this.currentTime
})
.onChange((time) => {
AvPlayerManager.seek(time)
})
.layoutWeight(1)
Text(this.formatTime(this.totalTime)) //歌曲总时间
.fontColor(Color.White)
}
.padding({ left: 10, right: 10, bottom: 20 })
// 控制按钮
Row() {
Image($r('app.media.ic_repeat'))
.width(30)
Image($r('app.media.ic_prev'))
.width(30)
.fillColor(Color.White)
.onClick(() => {
AvPlayerManager.pre()
})
Image(this.isplaying ? $r('app.media.ic_paused') : $r('app.media.ic_play'))
.width(45)
.fillColor(Color.White)
.onClick(() => {
if (this.isplaying == true) {
// 暂停歌曲
AvPlayerManager.pause()
// this.isplaying = false
} else {
// 播放歌曲
AvPlayerManager.reWork()
// this.isplaying = true
}
})
Image($r('app.media.ic_next'))
.width(30)
.fillColor(Color.White)
.onClick(() => {
AvPlayerManager.next()
})
Image($r('app.media.ic_song_list'))
.fillColor(Color.White)
.width(30)
.onClick(()=>{
this.h = 400
})
}
.width('100%')
.justifyContent(FlexAlign.SpaceAround)
.margin({ bottom: -30 })
}
.width('100%')
.justifyContent(FlexAlign.SpaceAround)
}
.justifyContent(FlexAlign.SpaceAround)
.height('100%')
.width('100%')
// 线性渐变
.linearGradient({
angle: 180, // 颜色从上往下变化
colors: [ // 渐变颜色数组
['#7f797a', 0.1], //灰色
['#b43038', 0.5], // 红色
['#b43038', 0.8], // 红色
['#b43038', 1], // 红色
]
})
// 播放歌曲列表容器
Column() {
// 上方
Row(){
Row({space:10}){
Image($r('app.media.ic_play'))
.height(25)
.fillColor('#d2577c')
Text('播放列表(16)')
.fontColor(Color.White)
.fontSize(18)
}
Image($r('app.media.ic_close'))
.height(25)
.onClick(()=>{
// 关闭列表容器
this.h = 0
})
}
.padding(20)
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
// 下方
List(){
ListItem(){
Row() {
Text('1')
.fontColor(Color.White)
.width(40)
.textAlign(TextAlign.Center)
Row({ space: 10 }) {
Column({space:5}) {
Text('歌曲名称')
.fontColor('#ff9fa0a1')
.fontSize(16)
.width('100%')
Text('作者')
.fontColor('#ff9fa0a1')
.fontSize(13)
.width('100%')
}
}
.layoutWeight(1)
Image($r('app.media.ic_more'))
.fillColor(Color.White)
.width(20)
}
.width('100%')
.padding({ top: 8, bottom: 8,right:10 })
}
}
}
.width('100%')
.height(this.h) //控制高度变化
.backgroundColor('#ff2c2c2c')
.animation({
duration:500 //控制动画显示
})
}
}
}
@State h:number = 0 //控制底部歌曲列表容器的高度
定义一个变量h,初始值为0
Image($r('app.media.ic_song_list'))
.fillColor(Color.White)
.width(30)
.onClick(()=>{
this.h = 400
})
第一次点击,h赋值为400的正常高度,歌曲列表正常出现
Image($r('app.media.ic_close'))
.height(25)
.onClick(()=>{
// 关闭列表容器
this.h = 0
})
再次点击,列表隐藏。
.width('100%')
.height(this.h) //控制高度变化
.backgroundColor('#ff2c2c2c')
.animation({
duration:500 //控制动画显示
})
然后增加过渡动画等属性,注意容器顺序别搞混。
4.歌曲列表数据动态化和背景雾化
同样在PlayPage页面
import { AvPlayerManager, songItemType } from '../services/AvPlayerManager'
import emitter from '@ohos.events.emitter'
@Entry
@Component
struct PlayPage {
@State angle: number = 0 // 控制角度变化值 0 - 360度改变
@State totalTime: number = 0
@State currentTime: number = 0
@State isplaying: boolean = true
@State currentMusic: songItemType = Object()
@State h: number = 0 //控制底部歌曲列表容器的高度
aboutToAppear() {
// 当页面进入的时候,将当前播放歌曲的数据赋值给全局变量currentMusci
this.currentMusic = AvPlayerManager.songs[AvPlayerManager.index]
// 注册emiiter接收上一首,下一首歌曲播放的时候新传入的歌曲对象
emitter.on({ eventId: 0 }, (res) => {
this.currentMusic = JSON.parse(res.data['item'])
})
// 不停的获取当前歌曲的已播放时长
AvPlayerManager.avPlayer.on('timeUpdate', (time) => {
if (AvPlayerManager.avPlayer.state == 'playing') {
this.isplaying = true
} else {
this.isplaying = false
}
// time表示当前歌曲已经播放的时长,单位是毫秒
this.currentTime = time
// 放到这里能够解决切歌时候不能获取最新歌曲的总时长问题
this.totalTime = AvPlayerManager.avPlayer.duration // 表示当前正在播放歌曲的总时间,单位是毫秒
})
}
// 作用:接收一个毫秒数值,转成成 00:00这种格式的字符串返回
formatTime(time: number) {
// 1. 计算出分钟数
let seconds = time / 1000 //将毫秒数转成总秒数
let min = Math.floor(seconds / 60) // 获取到了分钟部分
// 2. 计算出除开分钟之外的剩余的秒数
let s = Math.ceil(seconds % 60) // Math.ceil(19.89) -> 20
return `${min.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`
}
build() {
Stack(){
Image(this.currentMusic.img)
.height('100%')
.width('100%')
.blur(1000) // 将图片雾化-> 渐变
Stack({ alignContent: Alignment.Bottom }) {
Column() {
// CD唱片
Stack() {
Image($r('app.media.ic_cd'))
.height(300)
.borderRadius(300)
Image(this.currentMusic.img)
.height(200)
.borderRadius(200)
}
// 控制一个元素旋转 (这个属性一定要写在animation前面,否则不会触发动画)
.rotate({ angle: this.isplaying?this.angle:0 })
// 元素加载完毕之后触发一个回调函数 .onAppear
.onAppear(() => {
this.angle = 360 //将角度改成360都
})
// 增加旋转的动画效果
.animation({
duration: 10000, // 用10秒钟的时间让元素旋转一圈
curve: Curve.Linear, // 匀速旋转
iterations: -1 //表示设置旋转的圈数,如果是-1则表示不停的转,如果是正数则表示转的圈数
})
// 歌曲信息
Column({ space: 5 }) {
Text(this.currentMusic.name)
.fontSize(25)
.fontWeight(800)
.fontColor(Color.White)
Text(this.currentMusic.author)
.fontSize(15)
.fontColor(Color.White)
}
.width('100%')
// 播放进度+控制按钮容器
Column() {
// 播放进度
Row({ space: 5 }) {
Text(this.formatTime(this.currentTime)) // 当前进度时间
.fontColor(Color.White)
Slider({
min: 0,
max: this.totalTime,
value: this.currentTime
})
.onChange((time) => {
AvPlayerManager.seek(time)
})
.layoutWeight(1)
Text(this.formatTime(this.totalTime)) //歌曲总时间
.fontColor(Color.White)
}
.padding({ left: 10, right: 10, bottom: 20 })
// 控制按钮
Row() {
Image($r('app.media.ic_repeat'))
.width(30)
Image($r('app.media.ic_prev'))
.width(30)
.fillColor(Color.White)
.onClick(() => {
AvPlayerManager.pre()
})
Image(this.isplaying ? $r('app.media.ic_paused') : $r('app.media.ic_play'))
.width(45)
.fillColor(Color.White)
.onClick(() => {
if (this.isplaying == true) {
// 暂停歌曲
AvPlayerManager.pause()
// this.isplaying = false
} else {
// 播放歌曲
AvPlayerManager.reWork()
// this.isplaying = true
}
})
Image($r('app.media.ic_next'))
.width(30)
.fillColor(Color.White)
.onClick(() => {
AvPlayerManager.next()
})
Image($r('app.media.ic_song_list'))
.fillColor(Color.White)
.width(30)
.onClick(() => {
this.h = 400
})
}
.width('100%')
.justifyContent(FlexAlign.SpaceAround)
.margin({ bottom: -30 })
}
.width('100%')
.justifyContent(FlexAlign.SpaceAround)
}
.justifyContent(FlexAlign.SpaceAround)
.height('100%')
.width('100%')
// 线性渐变
// .linearGradient({
// angle: 180, // 颜色从上往下变化
// colors: [ // 渐变颜色数组
// ['#7f797a', 0.1], //灰色
// ['#b43038', 0.5], // 红色
// ['#b43038', 0.8], // 红色
// ['#b43038', 1], // 红色
// ]
// })
// 播放歌曲列表容器
Column() {
// 上方
Row() {
Row({ space: 10 }) {
Image($r('app.media.ic_play'))
.height(25)
.fillColor('#d2577c')
Text('播放列表(16)')
.fontColor(Color.White)
.fontSize(18)
}
Image($r('app.media.ic_close'))
.height(25)
.onClick(() => {
// 关闭列表容器
this.h = 0
})
}
.padding(20)
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
// 下方
List() {
ForEach(AvPlayerManager.songs, (item: songItemType, index: number) => {
ListItem() {
Row() {
Text((index+1).toString())
.fontColor(Color.White)
.width(40)
.textAlign(TextAlign.Center)
Row({ space: 10 }) {
Column({ space: 5 }) {
Text(item.name)
.fontColor(item.url == this.currentMusic.url
?'#d2577c':'#ff9fa0a1')
.fontSize(16)
.width('100%')
Text(item.author)
.fontColor(item.url == this.currentMusic.url
?'#d2577c':'#ff9fa0a1')
.fontSize(13)
.width('100%')
}
}
.layoutWeight(1)
Image($r('app.media.ic_more'))
.fillColor(Color.White)
.width(20)
}
.width('100%')
.padding({ top: 8, bottom: 8, right: 10 })
}
.onClick(() => {
AvPlayerManager.playMusic(item) // 播放歌曲
AvPlayerManager.sendMusicData(item) // 通知index.est更换歌曲信息
AvPlayerManager.index = index // 更新播放歌曲的索引
this.currentMusic = item // 改变当前歌曲数据
})
})
}
}
.width('100%')
.height(this.h)
.backgroundColor('#ff2c2c2c')
.animation({
duration: 500
})
}
}
}
}
Stack(){
Image(this.currentMusic.img)
.height('100%')
.width('100%')
.blur(1000) // 将图片雾化-> 渐变
使用层叠容器,给背景图片增加blur模糊属性,达到雾化效果。
Text(item.name)
.fontColor(item.url == this.currentMusic.url
?'#d2577c':'#ff9fa0a1')Text(item.author)
.fontColor(item.url == this.currentMusic.url
?'#d2577c':'#ff9fa0a1')
三元表达式实现点击歌曲后,歌曲与歌手名字动态改变颜色。
5.唱针效果
import { AvPlayerManager, songItemType } from '../services/AvPlayerManager'
import emitter from '@ohos.events.emitter'
@Entry
@Component
struct PlayPage {
@State angle: number = 0 // 控制角度变化值 0 - 360度改变
@State angle1: number = -55 // 控制唱针
@State totalTime: number = 0
@State currentTime: number = 0
@State isplaying: boolean = true
@State currentMusic: songItemType = Object()
@State h: number = 0 //控制底部歌曲列表容器的高度
aboutToAppear() {
// 当页面进入的时候,将当前播放歌曲的数据赋值给全局变量currentMusci
this.currentMusic = AvPlayerManager.songs[AvPlayerManager.index]
// 注册emiiter接收上一首,下一首歌曲播放的时候新传入的歌曲对象
emitter.on({ eventId: 0 }, (res) => {
this.currentMusic = JSON.parse(res.data['item'])
})
// 不停的获取当前歌曲的已播放时长
AvPlayerManager.avPlayer.on('timeUpdate', (time) => {
if (AvPlayerManager.avPlayer.state == 'playing') {
this.isplaying = true //表示当前正在播放歌曲
this.angle1 = -40
} else {
this.isplaying = false
this.angle1 = -55
}
// time表示当前歌曲已经播放的时长,单位是毫秒
this.currentTime = time
// 放到这里能够解决切歌时候不能获取最新歌曲的总时长问题
this.totalTime = AvPlayerManager.avPlayer.duration // 表示当前正在播放歌曲的总时间,单位是毫秒
})
}
// 作用:接收一个毫秒数值,转成成 00:00这种格式的字符串返回
formatTime(time: number) {
// 1. 计算出分钟数
let seconds = time / 1000 //将毫秒数转成总秒数
let min = Math.floor(seconds / 60) // 获取到了分钟部分
// 2. 计算出除开分钟之外的剩余的秒数
let s = Math.ceil(seconds % 60) // Math.ceil(19.89) -> 20
return `${min.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`
}
build() {
Stack(){
Image(this.currentMusic.img)
.height('100%')
.width('100%')
.blur(1000) // 将图片雾化-> 渐变
Stack({ alignContent: Alignment.Bottom }) {
Column() {
Stack({alignContent:Alignment.Top}){
// CD唱片
Stack() {
Image($r('app.media.ic_cd'))
.height(300)
.borderRadius(300)
Image(this.currentMusic.img)
.height(200)
.borderRadius(200)
}
// 控制一个元素旋转 (这个属性一定要写在animation前面,否则不会触发动画)
.rotate({ angle: this.isplaying?this.angle:0 })
// 元素加载完毕之后触发一个回调函数 .onAppear
.onAppear(() => {
this.angle = 360 //将角度改成360都
})
// 增加旋转的动画效果
.animation({
duration: 10000, // 用10秒钟的时间让元素旋转一圈
curve: Curve.Linear, // 匀速旋转
iterations: -1 //表示设置旋转的圈数,如果是-1则表示不停的转,如果是正数则表示转的圈数
})
// 唱针
Image($r('app.media.ic_stylus'))
.height(220)
.margin({top:-60})
.rotate({
angle:this.angle1, //旋转角度,调整过后发现 -40°可以落到cd唱片上,-55°离开cd唱片
centerX:110, // 设置旋转的中心点的x位置
centerY:30 // 设置旋转的中心点的y位置
})
.animation({
duration:500 //这里表示角度变化是在500毫秒以内完成
})
}
// 歌曲信息
Column({ space: 5 }) {
Text(this.currentMusic.name)
.fontSize(25)
.fontWeight(800)
.fontColor(Color.White)
Text(this.currentMusic.author)
.fontSize(15)
.fontColor(Color.White)
}
.width('100%')
// 播放进度+控制按钮容器
Column() {
// 播放进度
Row({ space: 5 }) {
Text(this.formatTime(this.currentTime)) // 当前进度时间
.fontColor(Color.White)
Slider({
min: 0,
max: this.totalTime,
value: this.currentTime
})
.onChange((time) => {
AvPlayerManager.seek(time)
})
.layoutWeight(1)
Text(this.formatTime(this.totalTime)) //歌曲总时间
.fontColor(Color.White)
}
.padding({ left: 10, right: 10, bottom: 20 })
// 控制按钮
Row() {
Image($r('app.media.ic_repeat'))
.width(30)
Image($r('app.media.ic_prev'))
.width(30)
.fillColor(Color.White)
.onClick(() => {
AvPlayerManager.pre()
})
Image(this.isplaying ? $r('app.media.ic_paused') : $r('app.media.ic_play'))
.width(45)
.fillColor(Color.White)
.onClick(() => {
if (this.isplaying == true) {
// 暂停歌曲
AvPlayerManager.pause()
// this.isplaying = false
} else {
// 播放歌曲
AvPlayerManager.reWork()
// this.isplaying = true
}
})
Image($r('app.media.ic_next'))
.width(30)
.fillColor(Color.White)
.onClick(() => {
AvPlayerManager.next()
})
Image($r('app.media.ic_song_list'))
.fillColor(Color.White)
.width(30)
.onClick(() => {
this.h = 400
})
}
.width('100%')
.justifyContent(FlexAlign.SpaceAround)
.margin({ bottom: -30 })
}
.width('100%')
.justifyContent(FlexAlign.SpaceAround)
}
.justifyContent(FlexAlign.SpaceAround)
.height('100%')
.width('100%')
// 线性渐变
.linearGradient({
angle: 180, // 颜色从上往下变化
colors: [ // 渐变颜色数组
['#7f797a', 0.1], //灰色
['#b43038', 0.5], // 红色
['#b43038', 0.8], // 红色
['#b43038', 1], // 红色
]
})
// 播放歌曲列表容器
Column() {
// 上方
Row() {
Row({ space: 10 }) {
Image($r('app.media.ic_play'))
.height(25)
.fillColor('#d2577c')
Text('播放列表(16)')
.fontColor(Color.White)
.fontSize(18)
}
Image($r('app.media.ic_close'))
.height(25)
.onClick(() => {
// 关闭列表容器
this.h = 0
})
}
.padding(20)
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
// 下方
List() {
ForEach(AvPlayerManager.songs, (item: songItemType, index: number) => {
ListItem() {
Row() {
Text((index+1).toString())
.fontColor(Color.White)
.width(40)
.textAlign(TextAlign.Center)
Row({ space: 10 }) {
Column({ space: 5 }) {
Text(item.name)
.fontColor(item.url == this.currentMusic.url
?'#d2577c':'#ff9fa0a1')
.fontSize(16)
.width('100%')
Text(item.author)
.fontColor(item.url == this.currentMusic.url
?'#d2577c':'#ff9fa0a1')
.fontSize(13)
.width('100%')
}
}
.layoutWeight(1)
Image($r('app.media.ic_more'))
.fillColor(Color.White)
.width(20)
}
.width('100%')
.padding({ top: 8, bottom: 8, right: 10 })
}
.onClick(() => {
AvPlayerManager.playMusic(item) // 播放歌曲
AvPlayerManager.sendMusicData(item) // 通知index.est更换歌曲信息
AvPlayerManager.index = index // 更新播放歌曲的索引
this.currentMusic = item // 改变当前歌曲数据
})
})
}
}
.width('100%')
.height(this.h)
.backgroundColor('#ff2c2c2c')
.animation({
duration: 500
})
}
}
}
}
@State angle1: number = -55 // 控制唱针
定义变量angle1,赋值-55,
if (AvPlayerManager.avPlayer.state == 'playing') {
this.isplaying = true //表示当前正在播放歌曲
this.angle1 = -40
} else {
this.isplaying = false
this.angle1 = -55
}
之后判断歌曲状态,如果正在播放,angle1 = -40,唱针转动到唱片上,如果未播放,angle1 = -55,唱针离开唱片。
6.结语
至此,鸿蒙开发主要页面和功能介绍完毕,发现页面和推荐页面实现和前面几个页面类似,不再讲述,如果想要学习新的功能,可以自行搜索学习。
后续还有新的功能的话,我会持续在该栏更新。