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

目录

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

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

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

相关推荐
python算法(魔法师版)3 小时前
.NET 在鸿蒙系统上的适配现状
华为od·华为·华为云·.net·wpf·harmonyos
bestadc4 小时前
鸿蒙 UIAbility组件与UI的数据同步和窗口关闭
harmonyos
枫叶丹45 小时前
【HarmonyOS Next之旅】DevEco Studio使用指南(二十二)
华为·harmonyos·deveco studio·harmonyos next
ax一号街阿楠7 小时前
华为FAT AP配置 真机
网络·华为·智能路由器
吗喽对你问好7 小时前
华为5.7机考第一题充电桩问题Java代码实现
java·华为·排序
乱世刀疤9 小时前
深度 |国产操作系统“破茧而出”:鸿蒙电脑填补自主生态空白
华为·harmonyos
博睿谷IT99_14 小时前
华为HCIP-AI认证考试版本更新通知
人工智能·华为
连续讨伐14 小时前
ensp的华为小实验
华为
沙振宇15 小时前
【Web】使用Vue3开发鸿蒙的HelloWorld!
前端·华为·harmonyos
嘿嘿-g1 天前
华为IP(6)
网络·tcp/ip·华为