<a href="#%E5%89%8D%E8%A8%80">前言</a>
<a href="#%E4%B8%80lrc%E6%AD%8C%E8%AF%8D%E6%96%87%E4%BB%B6%E7%AE%80%E4%BB%8B">一LRC歌詞檔案簡介</a>
<a href="#1%E4%BB%80%E4%B9%88%E6%98%AFlrc%E6%AD%8C%E8%AF%8D%E6%96%87%E4%BB%B6">1什麼是LRC歌詞檔案</a>
<a href="#2lrc%E6%AD%8C%E8%AF%8D%E6%96%87%E4%BB%B6%E7%9A%84%E6%A0%BC%E5%BC%8F">2LRC歌詞檔案的格式</a>
<a href="#lrc%E6%AD%8C%E8%AF%8D%E6%96%87%E4%BB%B6%E7%9A%84%E6%A0%87%E7%AD%BE%E7%B1%BB%E5%9E%8B">LRC歌詞檔案的标簽類型</a>
<a href="#1%E6%A0%87%E8%AF%86%E6%A0%87%E7%AD%BE">1辨別标簽</a>
<a href="#2%E6%97%B6%E9%97%B4%E6%A0%87%E7%AD%BE">2時間标簽</a>
<a href="#%E4%BA%8C%E8%A7%A3%E6%9E%90lrc%E6%AD%8C%E8%AF%8D">二解析LRC歌詞</a>
<a href="#1%E8%AF%BB%E5%8F%96%E5%87%BA%E6%AD%8C%E8%AF%8D%E6%96%87%E4%BB%B6">1讀取出歌詞檔案</a>
<a href="#2%E8%A7%A3%E6%9E%90%E5%BE%97%E5%88%B0%E7%9A%84%E6%AD%8C%E8%AF%8D%E5%86%85%E5%AE%B9">2解析得到的歌詞内容</a>
<a href="#1%E8%A1%A8%E7%A4%BA%E6%AF%8F%E8%A1%8C%E6%AD%8C%E8%AF%8D%E5%86%85%E5%AE%B9%E7%9A%84%E5%AE%9E%E4%BD%93%E7%B1%BBlrcrow">1表示每行歌詞内容的實體類LrcRow</a>
<a href="#2%E8%A7%A3%E6%9E%90%E6%AD%8C%E8%AF%8D%E7%9A%84%E6%9E%84%E9%80%A0%E5%99%A8">2解析歌詞的構造器</a>
<a href="#ilrcbuilder%E6%8E%A5%E5%8F%A3">ILrcBuilder接口</a>
<a href="#defaultlrcbuilder%E6%AD%8C%E8%AF%8D%E8%A7%A3%E6%9E%90%E6%9E%84%E9%80%A0%E5%99%A8">DefaultLrcBuilder歌詞解析構造器</a>
<a href="#lrc%E6%AD%8C%E8%AF%8D%E5%8E%9F%E5%A7%8B%E5%86%85%E5%AE%B9">lrc歌詞原始内容</a>
<a href="#lrc%E6%AD%8C%E8%AF%8D%E8%A7%A3%E6%9E%90%E5%90%8E%E7%9A%84%E5%86%85%E5%AE%B9">lrc歌詞解析後的内容</a>
<a href="#%E4%B8%89%E6%98%BE%E7%A4%BAlrc%E6%AD%8C%E8%AF%8D%E5%86%85%E5%AE%B9">三顯示LRC歌詞内容</a>
<a href="#1%E5%AE%9A%E4%B9%89%E4%B8%80%E4%B8%AAilrcviewlistener%E6%8E%A5%E5%8F%A3">1定義一個ILrcViewListener接口</a>
<a href="#2%E5%AE%9A%E4%B9%89%E4%B8%80%E4%B8%AAilrcview%E6%8E%A5%E5%8F%A3">2定義一個ILrcView接口</a>
<a href="#3%E8%87%AA%E5%AE%9A%E4%B9%89%E4%B8%80%E4%B8%AAlrcview">3自定義一個LrcView</a>
<a href="#%E5%90%8C%E6%AD%A5%E6%98%BE%E7%A4%BA%E6%AD%8C%E8%AF%8D%E5%8A%9F%E8%83%BD">同步顯示歌詞功能</a>
<a href="#%E6%8B%96%E5%8A%A8%E6%AD%8C%E8%AF%8D%E7%9A%84%E5%8A%9F%E8%83%BD">拖動歌詞的功能</a>
<a href="#%E7%BC%A9%E6%94%BE%E6%AD%8C%E8%AF%8D%E7%9A%84%E5%8A%9F%E8%83%BD">縮放歌詞的功能</a>
<a href="#lrcview%E7%9A%84%E5%85%A8%E9%83%A8%E4%BB%A3%E7%A0%81%E5%A6%82%E4%B8%8B%E6%89%80%E7%A4%BA">LrcView的全部代碼如下所示</a>
<a href="#mainactivity%E4%BB%A3%E7%A0%81%E5%A6%82%E4%B8%8B%E6%89%80%E7%A4%BA">MainActivity代碼如下所示</a>
<a href="#%E5%9B%9B%E9%A1%B9%E7%9B%AE%E6%BA%90%E7%A0%81%E5%9C%B0%E5%9D%80">四項目源碼位址</a>
作者:歐陽鵬 歡迎轉載,與人分享是進步的源泉! 轉載請保留原文位址: <a href="http://blog.csdn.net/ouyang_peng/article/details/50813419">http://blog.csdn.net/ouyang_peng/article/details/50813419</a>

最近有個項目有關于播放音樂時候,關于歌詞有以下幾個功能: 1、實作歌詞同步滾動的功能,即歌曲播放到哪句歌詞,就高亮地顯示出正在播放的這個歌詞; 2、實作上下拖動歌詞時候,可以拖動播放器的進度。即可以不停地上下拖動歌詞,當手指離開螢幕時候 即從目前拖動到的歌詞位置播放。 3、實作歌詞的字型大小可以進行縮放的功能。即雙指在螢幕進行縮放操作時,歌詞的字型大小也進行相應的縮放操作。
下面我将這幾個功能做成一個demo來展示給大家。首先來看看這個demo的具體實作效果,如下面幾幅圖所示。
圖1、同步滾動歌詞
圖2、上下拖動歌詞1
圖3、上下拖動歌詞2
圖4、縮放歌詞
圖5、歌詞顯示(較大字型)
圖6、歌詞顯示(較小字型)
圖7、歌詞滾動時候,高亮地畫出正滾動到的歌詞内容以及歌詞的開始時間,并該句歌詞下面畫出一條直線
lrc是英文lyric(歌詞)的縮寫,被用做歌詞檔案的擴充名。以lrc為擴充名的歌詞檔案可以在各類數位播放器中同步顯示。
先來看一份标準的LRC歌詞檔案,下面展示的是王力宏的《依然愛你》的lrc歌詞的内容
lrc歌詞文本中含有兩類标簽:一是辨別标簽 ,二是時間标簽。
辨別标簽,其格式為“[辨別名:值]”,主要包含以下預定義的标簽:
[ar:歌手名] [ti:歌曲名] [al:專輯名] [by:編輯者(指lrc歌詞的制作人)] [offset:時間補償值] (其機關是毫秒,正值表示整體提前,負值相反。這是用于總體調整顯示快慢的,但多數的MP3可能不會支援這種标簽)。
時間标簽,形式為“[mm:ss]”或“[mm:ss.ff]”(分鐘數:秒數.毫秒數),數字須為非負整數, 比如”[12:34.50]”是有效的,而”[0x0C:-34.50]”無效。 時間标簽需位于某行歌詞中的句首部分,一行歌詞可以包含多個時間标簽 (比如歌詞中的疊句部分)。當歌曲播放到達某一時間點時,MP3就會尋找對應的時間标簽并顯示标簽後面的歌詞文本,這樣就完成了“歌詞同步”的功能。
例如下面的這首 草蜢的《失戀戰線聯盟》,就是一行歌詞包含了多個時間标簽。
[01:43.33][00:16.27]她總是隻留下電話号碼 上面這行歌詞表示: 在 [00:16.27] 這個時間點播放 “她總是隻留下電話号碼” 這句歌詞, 在 [01:43.33] 這個時間點再一個播放 “她總是隻留下電話号碼” 這句歌詞。
其實可以把上面這行歌詞拆分為下面兩句歌詞:
例如:從assets目錄下讀取test.lrc歌詞檔案内容,則可以調用上面的getFromAssets(String fileName)方法得到歌詞的文本内容,如下所示:
首先封裝一個表示每行歌詞内容的實體類LrcRow,該類由三個屬性,分别為:
strTime、time、content。
例如一行歌詞内容為:[02:34.14]當你我不小心又想起她 , 解析該行歌詞後的實體類LrcRow的屬性如下所示:
strTime表示該行歌詞要開始播放的時間,格式如下:[02:34.14]
time表示将strTime轉換為long型之後的數值
例如将strTime為[02:34.14]格式轉換154014(154014=02 * 60 * 1000 + 34 * 1000+14)
content表示該行歌詞的内容,如:當你我不小心又想起她
代碼如下:
該LrcRow的List createRows(String standardLrcLine)方法 ,将循環地一行一行的去讀取歌詞的内容。然後對每一行的歌詞進行解析,每解析出一個時間标簽[XX:XX.XX]則new出一個LrcRow對象,然後加入到歌詞行List集合中去。
該LrcRow類實作Comparable接口,用來進行解析之後的排序操作,排序按時間從小到大排序。
定義一個ILrcBuilder接口,接口有一個List getLrcRows(String rawLrc)方法,該方法用來解析歌詞,得到LrcRow的集合
DefaultLrcBuilder實作ILrcBuilder接口,List getLrcRows(String rawLrc)方法會循環地讀取歌詞的每一行,然後調用LrcRow類的List createRows(String standardLrcLine)方法,得到解析每一行歌詞之後的LrcRow集合,再将每一行得到LrcRow集合中得到的LrcRow實體加入一個總 的到LrcRow集合rows中去,然後将rows集合根據歌詞行的時間排序,得到排序後的LrcRow集合,該集合就是最終的解析歌詞後的内容了。
例如:通過下面代碼來調用ILrcBuilder解析歌詞,
草蜢的《失戀戰線聯盟》,lrc原始内容如下:
讀取該歌詞内容,過程中的列印日志為:
即,草蜢的《失戀戰線聯盟》的lrc歌詞解析完後的内容如下:
下面是解析歌詞前後的對比圖
至此,歌詞解析完畢!
ILrcViewListener接口,該接口定義了一個onLrcSeeked方法用來監聽使用者上下拖動歌詞的動作定義了一個方法
onLrcSeeked(int newPosition, LrcRow row)
當歌詞被使用者上下拖動的時候回調該方法
ILrcView接口接口,定義了三個方法
setLrc(List lrcRows)
調用該方法設定要展示的歌詞行集合
seekLrcToTime(long time)
音樂播放的時候調用該方法滾動歌詞,高亮正在播放的那句歌詞
setListener(ILrcViewListener l)
調用該方法設設定歌詞拖動時候的監聽類,用以回調ILrcViewListener的onLrcSeeked(int newPosition, LrcRow row)方法
自定義一個LrcView,該LrcView繼承android.view.View對象,實作了ILrcView接口。該自定義LrcView可以實作了同步顯示歌詞,拖動歌詞,縮放歌詞等功能。
首先來說說顯示歌詞的實作思路,要顯示歌詞即把歌詞的内容繪制出來,可以分以下三步來繪制歌詞:
第1步:高亮地畫出正在播放的那句歌詞 第2步:畫出正在播放的那句歌詞的上面可以展示出來的歌詞 第3步:畫出正在播放的那句歌詞的下面的可以展示出來的歌詞
重寫onDraw(Canvas canvas)方法,在方法中按照上面的思路來繪制者三部分的歌詞。代碼如下:
為了實作同步顯示功能的功能,則需要不停地将自定義的LrcView進行重繪。首先當MediaPlayer開始播放的時候,同步的啟動一個TimerTask來進行歌詞的滾動操作。如代碼所示:
上面代碼的意思是,當MediaPlayer開始播放的時候,啟動一個定時器Timer,然後通過這個定時器每隔mPalyTimerDuration時間來執行一次LrcTask任務。LrcTask的代碼如下:
上面的代碼是:首先擷取MediaPlayer的播放進度值,然後調用了LrcView的seekLrcToTime(long time)方法進行歌詞同步滾動,LrcView的seekLrcToTime(long time)方法的實作代碼如下:
上面代碼意思是,首先通過傳入進來的MediaPlayer的播放進度值,來判斷需要高亮地歌詞行LrcRow是哪一行,然後調用seekLrc(int position, boolean cb)方法來進行歌詞重繪操作。seekLrc(int position, boolean cb)方法的實作如下所示:
上面方法是将要高亮的歌詞行設定為目前正在播放的歌詞行,然後重繪LrcView。
要實作拖動歌詞的功能,可以分為以下幾步來實作
1、給LrcView注冊一個ILrcViewListener監聽接口。
下面是LrcView注冊ILrcViewListener監聽的具體實作。
2、當歌詞進行拖動的時候,回調ILrcViewListener接口的onLrcSeeked(int newPosition, LrcRow row)方法。
如下面代碼所示:回調了onLrcSeeked(int newPosition, LrcRow row)方法。
3、判斷手指在螢幕上的操作,來進行歌詞滾動的操作。
重寫onTouchEvent(MotionEvent event)方法,來判斷手指的操作是拖動歌詞還是縮放歌詞。
如上代碼所示,當一個手指移動的時候,則調用doSeek(MotionEvent event)方法來進行拖動歌詞的操作,doSeek(MotionEvent event)方法的具體實作代碼如下:
如上面代碼所示,當一個手指不停的在螢幕上移動時,将會不停地調用doSeek(MotionEvent event)方法來進行LrcView的重繪操作,進而實作了歌詞拖動的效果。
當手指離開螢幕的時候,即MotionEvent 為MotionEvent.ACTION_UP的時候,會調用seekLrc(int position, boolean cb)方法,進而回調ILrcViewListener接口的onLrcSeeked方法,來拖動MediaPlayer的播放進度值,進而達到了拖動歌詞後從最終高亮的歌詞開始重新播放歌詞的功能。如下代碼所示:
如onTouchEvent(MotionEvent event)方法中所示,當兩個手指在螢幕上移動的時候,調用doScale(MotionEvent event)方法來做縮放歌詞的功能。
doScale(MotionEvent event)方法的具體實作代碼如下所示:
如上代碼所示,當兩個手指第一次放在螢幕上時候,調用setTwoPointerLocation(MotionEvent event)方法來記錄兩個手指的x坐标和y坐标,setTwoPointerLocation(MotionEvent event)方法代碼如下所示:
當兩個手指在螢幕上移動的時候,調用getScale(MotionEvent event)方法來對比兩個手指前後兩次的x坐标和y坐标,進而得到要縮放的比例scaleSize。getScale(MotionEvent event)方法具體實作如下所示:
當通過getScale(MotionEvent event)方法獲得了縮放比scaleSize後,調用setNewFontSize(int scaleSize)來設定歌詞的新的字型大小,然後重繪LrcView,進而實作了縮放歌詞的功能。
setNewFontSize(int scaleSize)方法的具體實作如下所示:
至此,縮放功能已經實作。
以上就是自定義LrcView的全部内容,下面将該自定義LrcView放在布局檔案activity_main.xml中去顯示出來。
activity_main.xml的代碼如下所示:
然後通過MainActivity來加載該布局,并在MainActivity中播放音樂,MainActivity的代碼如下所示:
下面是項目的結構圖。
CSDN下載下傳
項目的源代碼可以從下面的位址去免費下載下傳:
<a href="http://download.csdn.net/detail/qq446282412/9453906">http://download.csdn.net/detail/qq446282412/9453906</a>
Github下載下傳
<a href="https://github.com/ouyangpeng/android-lrc-view-oyp">https://github.com/ouyangpeng/android-lrc-view-oyp</a>
