Android自定义View,高仿QQ音乐歌词滚动控件!

news/2025/1/13 7:54:58/

最近在以QQ音乐为样板做一个手机音乐播放器,源码下篇博文放出。今天我想聊的是这个QQ音乐播放器中歌词显示控件的问题,和小伙伴们一起来探讨怎么实现这个歌词滚动的效果。OK,废话不多说,先来看看效果图:

好,接下来我们就来看看怎么实现这样一个效果。本文主要包括如下几方面内容:


1.歌词文件格式分析及解析

2.歌词显示控件绘制

3.关于卡拉OK模式

4.使用方式


好,那就开始吧。

1.歌词文件格式分析及解析

首先,小伙伴们需要明白歌词文件的格式都是固定的,是什么样子的呢,我们来看看下图:


我们一个歌词文件打开都是这种格式,前面  []  中的是该行歌词显示的时间,后面一行是歌词,只有时间没有歌词的行就是伴奏时间。了解了这固定的歌词格式,剩下的就简单了,解析这段文本就行了。我创建一个LrcBean用来存放每一行的数据,这个LrcBean中包括三个属性,分别是一句歌词,该歌词开始唱的时间,该歌词唱完的时间,咦,有的小伙伴可能有疑问,唱完是什麽时候呢?就是下一句的开始时间呗。OK,那我们来看看实体类:

public class LrcBean {private String lrc;private long start;private long end;public LrcBean() {}public LrcBean(String text, long start, long end) {this.lrc = text;this.start = start;this.end = end;}public String getLrc() {return lrc;}public void setLrc(String lrc) {this.lrc = lrc;}public long getStart() {return start;}public void setStart(long start) {this.start = start;}public long getEnd() {return end;}public void setEnd(long end) {this.end = end;}
}

OK,实体类有了,接下来我们来看看实体类怎么解析歌词文本,解析过程分为两步:

1.考虑到歌词文本中可能有转义字符,我们需要先把转义字符还原

2.然后按照换行符将文本拆分,再通过字符串截取将每一行的数据提取出来。代码如下(由于转义字符显示不出来,所以我这里贴一张代码图,源码文末可以下载):


OK,通过以上方式我们就把歌词文件解析成了一个List集合,该集合中的每一项就是一句歌词,另外,在伴奏的时间段,我显示一句music。

2.歌词显示控件绘制

歌词解析完了,接下来我们就可以绘制歌词View了。绘制的整体思路是这样:

1.首先获取当前播放的时间

2.根据当前播放时间,遍历歌词的List集合,判断出当前正在播放的是List集合中的哪一句,找到该句的下标

3.遍历歌词List集合,绘制所有歌词,绘制的过程中,如果该句是正在播放的歌词,则使用高亮的画笔来绘制,否则使用普通画笔绘制。

4.判断当前是否已经换行了,如果是,则调用setScrollY方法让屏幕滚动一行。关于setScrollY方法如果小伙伴们还不太了解可以参考这篇文章View绘制详解(五),draw方法细节详解之View的滚动/滑动问题。

5.每隔100毫秒重绘View。

OK,整个流程就是这样,接下来我们来看看代码实现:

    @Overrideprotected void onDraw(Canvas canvas) {if (width == 0 || height == 0) {width = getMeasuredWidth();height = getMeasuredHeight();}if (list == null || list.size() == 0) {canvas.drawText("暂无歌词", width / 2, height / 2, gPaint);return;}getCurrentPosition();int currentMillis = player.getCurrentPosition();drawLrc2(canvas);long start = list.get(currentPosition).getStart();float v = (currentMillis - start) > 500 ? currentPosition * 80 : lastPosition * 80 + (currentPosition - lastPosition) * 80 * ((currentMillis - start) / 500f);setScrollY((int) v);if (getScrollY() == currentPosition * 80) {lastPosition = currentPosition;}postInvalidateDelayed(100);}private void drawLrc2(Canvas canvas) {for (int i = 0; i < list.size(); i++) {if (i == currentPosition) {canvas.drawText(list.get(i).getText(), width / 2, height / 2 + 80 * i, hPaint);} else {canvas.drawText(list.get(i).getText(), width / 2, height / 2 + 80 * i, gPaint);}}}private void getCurrentPosition() {try {int currentMillis = player.getCurrentPosition();if (currentMillis < list.get(0).getStart()) {currentPosition = 0;return;}if (currentMillis > list.get(list.size() - 1).getStart()) {currentPosition = list.size() - 1;return;}for (int i = 0; i < list.size(); i++) {if (currentMillis >= list.get(i).getStart() && currentMillis < list.get(i).getEnd()) {currentPosition = i;return;}}} catch (Exception e) {
//            e.printStackTrace();postInvalidateDelayed(100);}}

OK,这里给出一个核心代码,完整代码小伙伴们在文末可以自行下载。

3.关于卡拉OK模式

OK,经过第二个步骤之后,我们这个歌词控件已经可以根据当前播放的时间来显示高亮的歌词,同时进行歌词的滚动。有的小伙伴可能还想实现一种类似于KTV里边的那种播放效果,我们也来看一看怎么实现。还是先来说说思路吧。

1.把所有的歌词都用普通的画笔画出来

2.为当前正在播放的歌词生成一个Bitmap

3.根据当前播放时间,计算出该句歌词播放的比例,然后根据这个比例绘制第二步生成的Bitmap。

OK,根据上述的思路,我贴出核心代码如下:

for (int i = 0; i < list.size(); i++) {canvas.drawText(list.get(i).getLrc(), width / 2, height / 2 + 80 * i, gPaint);}String highLineLrc = list.get(currentPosition).getLrc();int highLineWidth = (int) gPaint.measureText(highLineLrc);int leftOffset = (width - highLineWidth) / 2;LrcBean lrcBean = list.get(currentPosition);long start = lrcBean.getStart();long end = lrcBean.getEnd();int i = (int) ((currentMillis - start) * 1.0f / (end - start) * highLineWidth);if (i > 0) {Bitmap textBitmap = Bitmap.createBitmap(i, 80, Bitmap.Config.ARGB_8888);Canvas textCanvas = new Canvas(textBitmap);textCanvas.drawText(highLineLrc, highLineWidth / 2, 80, hPaint);canvas.drawBitmap(textBitmap, leftOffset, height / 2 + 80 * (currentPosition - 1), null);}

4.使用方式

OK,控件做好了,最后我们再来看看使用方式。很简单,引入这个View 的类库(文末会给出下载地址),然后传入歌词的文本,开启绘制即可,如下:

lrcView.setLrc(lrcStr);lrcView.setPlayer(PlayUtil.player);lrcView.init();

简单三行代码,就可以开始使用了。


项目地址https://github.com/lenve/LrcView




http://www.ppmy.cn/news/626310.html

相关文章

Scrapy爬取QQ音乐、评论、下载、歌曲、歌词

文章目录 Scrapy爬取QQ音乐、评论、下载、歌曲、歌词爬取分析1、分析页面的歌手信息2、编写代码Item.py中编写爬取的信息setting.py中的配置信息Spider下的music.py编写代码 3、分析歌单列表在music.py中继续编程 4、分析歌词请求爬取歌词代码的编写歌词信息的清洗 5、分析评论…

QQ音乐中任何歌曲完全免费下载方法

喜欢在玩电脑的时候开着QQ音乐,往往听到好歌就想把它扔P3里边去但QQ自带的下载功能要开通绿钻才能用,且有些歌曲还不开放下载,于是我就开始找下载的方法最开始就是右键点歌曲__搜索__按歌曲,在SOSO搜索结果中找它的URL地址,复制到迅雷中下载但有些最新的歌在SOSO中搜不到,而且现…

网易云音乐云盘存歌曲加歌词

网易云云盘存歌曲加歌词 目录 网易云云盘存歌曲加歌词解决办法成功效果编写歌曲文件第一种第二种 其他问题补充 问题&#xff1a;我们从网上下载的音乐存在网易云音乐云盘时&#xff0c;是没有歌词的如下图 解决办法 解决办法&#xff1a; 第一&#xff1a;先删除没有歌词的那…

ChatGPT是否可以写出一篇论文

利用AI反哺教育和学术&#xff0c;在训练它写论文的过程中你学到的&#xff0c;比你自己写一篇论文学到的更多。让工具回归工具&#xff0c;让我们变成更好的我们&#xff01; 第一步&#xff1a;现象确认 第二步&#xff1a;学术概念化 第三步&#xff1a;定位优质的学术资源 …

Nginx Rewrite的应用

目录 一、Nginx Rewrite 二、Rewrite的功能 1.Rewrite 跳转场景 2.Rewrite 跳转实现 3.Rewrite 实际场景 4.Rewrite 正则表达式 5.Rewrite 命令/语法格式 6.location 分类 7.location 优先级 8.Rewrite和location比较 9.根据以上了解&#xff0c;小案例来操…

【Python爬虫】利用爬虫抓取双色球开奖号码,获取完整数据,简洁45行代码实现,更新时间2023-06-28

链接&#xff1a;https://pan.baidu.com/s/18oE308_NVNPaCOACw_H5Hw?pwdabc1 利用爬虫抓取双色球开奖号码&#xff0c;获取完整数据&#xff0c;简洁45行代码实现&#xff0c;更新时间2023-06-28 这是网上的数据&#xff0c;怎么将它爬取下来 它将只爬取最近30期的双色球开…

top命令三个负载是什么

在top命令中&#xff0c;“负载”&#xff08;load average&#xff09;是指系统在一段时间内的平均活跃进程数&#xff08;即平均的就绪态和运行态进程数&#xff09;。top命令默认显示三个负载值&#xff0c;分别对应于过去1分钟、5分钟和15分钟的统计。 这三个负载值代表系…

卡王谁知道要怎么用吗?

卡王谁知道要怎么用吗?