鸿蒙小案例-动态歌词

之前有个播放器要显示歌词,但没找到鸿蒙中现成的组件,只能摸索着自己写一个
先看下效果

鸿蒙动态歌词展示

原理其实很简单
首先布局什么的就不多说了,歌词显示这块肯定是要全部显示的,主要操作难点在于怎么根据播放时长动态跳转到歌词位置
在这里我们用个List组件包裹,并且绑定scroller滚动条,循环显示所有歌词,当播放到指定位置时,通过scrollToIndex方法跳到歌词的这一行由此实现动态歌词
拿到歌词后转换成两个长度一致的数组,分别为时间数组,歌词数组,他们的下标应该是一一对应的,
播放时长随时变动,一变动就去时间数组寻找最接近的那个值,拿到下标,然后用这个下标去用scroller的scrollToIndex方法跳到歌词的这一行
全局常量

lrcScroller: Scroller = new Scroller() //歌词滚动条
@State lrcKeys: number[] = [] //歌词时间数据
@State lrcValues: string[] = [] //歌词具体数据
@Watch('upPlayStatus')
@State playStartTime: number = 0 //当前播放起始时间
@State upPlayScrollerIndex: number = 0 //歌词滚动索引
@State upPlayIndex: number = 0 //歌词显示索引

显示代码

List({ initialIndex: 1, scroller: this.lrcScroller }) {
      ForEach(this.lrcValues, (item: string, index: number) => {
        ListItem() {
          Column() {
            Row() {
              Text(item)
                .fontColor(this.upPlayIndex === index ? '#00AE68' : '#000000')
                .fontSize(15)
                .maxLines(3)
                .textOverflow({ overflow: TextOverflow.Ellipsis })
                .padding(5)
                .fontWeight(this.upPlayIndex === index ? FontWeight.Bold : FontWeight.Normal)
                .textAlign(TextAlign.Center)
            }.borderRadius(5).backgroundColor('#F3F3FA')
            .margin({ bottom: 5 })
          }.alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center).width('100%')
        }
      })
    }.animation({ duration: 500 })

其中
this.lrcValues=歌词数组,结构为string
item = 具体的每一行的歌词,结构为string
index = 歌词数组的下标,结构为number
this.upPlayIndex = 当前播放的时间在歌词数组中的下标

歌词+时间获取代码

//获取歌词
  async queryLrcById() {
    let lrcMap: Map<string, string[] | number[]> = await CommUtils.queryLrcById(this.PlayState.id)
    this.lrcKeys = lrcMap.get('key') as number[]
    this.lrcValues = lrcMap.get('value') as string[]
  }

this.PlayState.id = 当前播放歌曲id
CommUtils.queryLrcById = 根据id获取歌词数据,返回的是两个数组,Map结构
this.lrcKeys = 时间数组
this.lrcValues = 歌词数组
这个方法应该是在你点击一个按钮,然后要显示歌词时调用

动态调整歌词

//显示歌词附带的滚动效果
  upPlayStatus() {
    if (this.lrcStatus && this.lrcKeys.length > 0) {
      const indexStr = CommUtils.findClosestNumber(this.lrcKeys, this.playStartTime)
      setTimeout(() => {
        this.upPlayIndex = this.lrcKeys.indexOf(indexStr)
        const index = this.upPlayIndex - 4 < 0 ? 0 : this.upPlayIndex - 4
        if (index > this.upPlayScrollerIndex) {
          this.lrcScroller.scrollToIndex(index)
          this.upPlayScrollerIndex = index
        }
      }, 1000)
    }
  }

this.playStartTime = 当前播放的歌曲的已播放时长
index = scroller需要滚动到的行数/下标
this.upPlayScrollerIndex = 上一个已经跳动的下标
通过@Watch装饰器来实现调用
为什么会有下面这块代码呢

if (index > this.upPlayScrollerIndex) {
    .......  
 }

因为歌词数据并不是连续的,它是跳着来的,有时候歌曲的伴奏,哼唱这些都是没有歌词的,但是我们的获取最相近下标那个方法是没做区分的,会有很多重复的index出现,所以我们在需要跳动前记录下跳动的坐标,在下一次跳动前加个判断,只有大于上一个下标的时候,我再去跳,小于等于的话就不去跳,节省下消耗
为什么会有定时器呢
因为获取最相近的下标并不太精准,我们延时一下再跳
为什么会有下标 减 4 呢?
因为list的scroller的scrollToIndex方法会直接置顶显示,我们减4 它就始终处于屏幕正中央(这里说明一下,要根据外围包裹组件的具体高度来调整,一屏能显示几行歌词,这里就减去 总行数除以2,否则它不会显示在正中间)
findClosestNumber方法如下

//获取一个数组中跟传入值最相近的数值
  static findClosestNumber(arr: number[], target: number) {
    return arr.reduce((p, c) => (Math.abs(target - c) < Math.abs(target - p) ? c : p))
  }

arr = 时间数组
target = 当前播放时间

到这里就基本上实现动态歌词的功能,当然还有一些细节需要自行去优化下
比如:
切歌后,这个index的值要等于0,滚动条要滚动到0,数组要等于0等。。。

//切歌时重置歌词相关组件
  clearLrcCom() {
    this.upPlayScrollerIndex = 0
    this.upPlayIndex = 0
    this.lrcValues = []
    this.lrcKeys = []
    this.lrcScroller.scrollToIndex(0)
  }

这个方法是要在切歌时,隐藏歌词时 调用

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
鸿蒙编译qemu-arm-linux产品时,没有生成vendor.img可能是因为以下几个原因: 首先,鸿蒙系统在编译时需要进行多个步骤,其中包括生成各个分区(分区包括system、vendor、boot等)。编译时如果没有指定生成vendor分区的操作,就不会在编译完成后生成vendor.img。 其次,可能是在编译鸿蒙系统时选择了一些定制化的配置,导致vendor分区没有被包含在生成的镜像中。鸿蒙系统提供了一些定制化选项,可以根据具体需求选择生成的分区。 另外,如果在编译过程中出现了错误或警告,可能导致编译过程中断,进而无法生成完整的镜像文件,其中也包括vendor.img。 要解决这个问题,可以尝试以下方法: 1. 确认编译过程中是否选择了生成vendor分区的选项,如果没有,需要重新编译时指定生成vendor分区。 2. 检查编译过程中是否出现了错误或警告,并解决其中可能导致编译中断的问题,确保编译过程可以顺利完成。 3. 检查编译使用的鸿蒙源码是否完整,如果有缺失或损坏的文件可能会导致编译过程中断,无法生成完整的镜像文件。 总结来说,如果在编译鸿蒙系统时没有生成vendor.img,首先需要确认编译过程中是否选择了生成vendor分区的选项,并检查编译过程中是否出现了错误或警告。如果以上检查均无问题,可以尝试重新编译鸿蒙系统并确保使用完整的鸿蒙源码。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

幻凡ss

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值