你们好,咱们是爱学啊,继上一篇讲解了【LRC歌词原理和实现高仿Android网易云音乐】,今天给你们带来一篇关于卡拉OK歌词原理和在Android上如何实现歌词逐字滚动的效果,本文来自【Android开发项目实战个人云音乐】课程。java
相信你们都懂一张图赛过千言万语。canvas
效果和如今市面上大部分播放器差很少,固然若是要运用到商业项目中,确定还须要进行一些优化,例如:滚动效果有弹性,字体大小,字体颜色等。架构
要明白什么是卡拉OK歌词,就先要搞明白什么是卡拉OK,简单来说就是卡拉OK是一种伴奏系统,演唱者能够在预先录制的音乐伴奏下参与唱歌,现多叫KTV(Karaoke);卡拉OK歌词默认格式为ksc,固然如今市面上的一些软件在他的基础上作了定制,具体的在咱们的课程中讲解了;咱们这里就讲解ksc,由于卡拉OK歌词的核心就是精确到每个字,因此搞明白他的原理,咱们也就能够在他的基础上定制了。学习
在实现歌词功能前,确定须要搞明白ksc歌词格式,例如:咱们找了一段LRC歌词:字体
karaoke := CreateKaraokeObject; karaoke.rows := 2; karaoke.TimeAfterAnimate := 2000; karaoke.TimeBeforeAnimate := 4000; karaoke.clear; karaoke.add('00:20.699', '00:27.055', '[●●●●●●]', '7356',RGB(255,0,0)); karaoke.add('00:27.487', '00:32.068', '一时失志难免怨叹', '347,373,1077,320,344,386,638,1096'); karaoke.add('00:33.221', '00:38.068', '一时落魄难免胆寒', '282,362,1118,296,317,395,718,1359'); karaoke.add('00:38.914', '00:42.164', '那通失去但愿', '290,373,348,403,689,1147'); karaoke.add('00:42.485', '00:44.530', '每日醉茫茫', '298,346,366,352,683'); karaoke.add('00:45.273', '00:49.029', '无魂有体亲像稻草人', '317,364,380,351,326,351,356,389,922'); karaoke.add('00:50.281', '00:55.585', '人生可比是海上的波浪', '628,1081,376,326,406,371,375,1045,378,318'); karaoke.add('00:56.007', '01:00.934', '有时起有时落', '303,362,1416,658,750,1438'); karaoke.add('01:02.020', '01:04.581', '好运歹运', '360,1081,360,760'); karaoke.add('01:05.283', '01:09.453', '总嘛要照起来行', '303,338,354,373,710,706,1386'); karaoke.add('01:10.979', '01:13.029', '三分天注定', '304,365,353,338,690'); karaoke.add('01:13.790', '01:15.950', '七分靠打拼', '356,337,338,421,708'); karaoke.add('01:16.339', '01:20.870', '爱拼才会赢', '325,1407,709,660,1430');
能够看到内容是用换行符分割的,若是这些数据是经过接口返回,而不是直接返回一个文件,那么这里面的换行符应该变为n换行符,这一点咱们也在课程中讲解到了。优化
每一行是一句歌词;每一行歌词又分为四部分:spa
第一部分:这一行开始时间 第二部分:这一行结束时间 第三部分:这一句歌词 第四部分:每一个字持续的毫秒
其中顶部的一些信息是元数据:不一样的播放器可能实现不同。rest
查看上面的歌词,咱们能够发现有大部分的重复内容,因此能够定制。code
将每行歌词前面的时间解析后,转为毫秒,这样播放器在播放的时候能够获取到播放时间,而后拿着时间查找当前时间对应哪一行歌词,而后在查看当前时间对应该行的哪个字,而后进行相应的绘制,具体的在能够有讲解。接口
歌词解析就很简单了,就是字符串拆分,因此就不贴代码了;但但愿你们在写代码的时候不要只局限于功能,也要注重架构;歌词有不少种,因此能够搞成用不一样的类来解析,对外暴露统一的接口;这部分在课程中有讲解。
不一样的平台也不同,咱们这里是Android,因此绘制用Canvas。咱们这里的思路是:歌词View的高度是固定的,因为咱们但愿当前行歌词始终显示到歌词View中间,因此先算出View的中心高度,而后在该位置绘制当前行歌词,这一步根据不一样的歌词处理的逻辑也不同,但歌词可分为两类,一类是逐行,一类是逐字,对于逐行来讲就直接绘制就好了,只是颜色,大小不同而已;逐字下一节讲解;而后从当前行歌词位置像前绘制歌词,直到超出View顶部为止,在从当前行歌词向下歌词绘制,直到超出View底部为止;当前你可使用LinearLayout添加全部歌词当前容器内,而后滚动。
相对于LRC歌词,只须要添加ksc格式格式时绘制:
if (lyric.isAccurate()) { //精确到字歌词,格式能够有不少种 //只是解析的时候不同,但都组成成通用的model //因此在歌词View中,咱们已经不须要知道是ksc,仍是QQ歌词,仍是酷狗歌词等。 canvas.drawText(line.getLineLyrics(), x, y, backgroundTextPaint); if (lyricCurrentWordIndex == -1) { //该行已经播放完了 lineLyricPlayedWidth = textWidth; } else { String[] lyricsWord = line.getLyricsWord(); int[] wordDuration = line.getWordDuration(); //获取当前时间前面的文字 String beforeText = line.getLineLyrics().substring(0, lyricCurrentWordIndex); float beforeTextWidth = getTextWidth(foregroundTextPaint, beforeText); //当前字 String currentWord = lyricsWord[lyricCurrentWordIndex]; float currentWordTextWidth = getTextWidth(foregroundTextPaint, currentWord); //当前字已经演唱的宽度 float currentWordWidth = currentWordTextWidth / wordDuration[lyricCurrentWordIndex] * wordPlayedTime; lineLyricPlayedWidth = beforeTextWidth + currentWordWidth; } canvas.save(); //裁剪一个矩形用来绘制已经唱的歌词 canvas.clipRect(x, y - textHeight, x + lineLyricPlayedWidth, y + textHeight); //这个矩形包是文字的高度+行高 //canvas.drawRect(x, y - textHeight, x + lineLyricPlayedWidth, // y + textHeight,foregroundTextPaint); canvas.drawText(line.getLineLyrics(), x, y, foregroundTextPaint); canvas.restore(); } else { //精确到行 }
歌词和LRC是同样的。
到这里歌词View核心功能基本就实现完成了,若是要深刻学习能够查看咱们的【高仿Android网易云音乐】课程,或者在线电子书【电子书】。