鸿蒙开发—黑马云音乐之播放页面(下)

目录

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.结语

至此,鸿蒙开发主要页面和功能介绍完毕,发现页面和推荐页面实现和前面几个页面类似,不再讲述,如果想要学习新的功能,可以自行搜索学习。

后续还有新的功能的话,我会持续在该栏更新。

相关推荐
俺不理解1 天前
鸿蒙 Stage Arkts HSP+HAR 的集成
华为·harmonyos·模块化·har·hsp
小雨青年1 天前
鸿蒙 HarmonyOS 6 | AI Kit 集成 CANN Kit 异构计算服务
人工智能·华为·harmonyos
酣大智1 天前
华为通用路由平台VRP
网络·华为
前端不太难1 天前
HarmonyOS 游戏卡顿,问题不在渲染
华为·状态模式·harmonyos
讯方洋哥1 天前
HarmonyOS App开发——一多图片浏览器应用App开发
华为·harmonyos
Miguo94well1 天前
Flutter框架跨平台鸿蒙开发——海龟汤APP的开发流程
flutter·华为·harmonyos·鸿蒙
讯方洋哥1 天前
HarmonyOS App开发——购物商城应用App开发
harmonyos
无穷小亮1 天前
Flutter框架跨平台鸿蒙开发——Excel函数教程APP的开发流程
flutter·华为·excel·harmonyos·鸿蒙
无穷小亮1 天前
Flutter框架跨平台鸿蒙开发——打字练习APP开发流程
flutter·华为·harmonyos·鸿蒙
九 龙1 天前
Flutter框架跨平台鸿蒙开发——水电缴费提醒APP的开发流程
flutter·华为·harmonyos·鸿蒙