你們好,咱們是愛學啊,繼上一篇講解了【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網易雲音樂】課程,或者在線電子書【電子書】。