Android自定義View來實現解析lrc歌詞同步滾動、上下拖動、縮放歌詞等功能
http://blog.csdn.net/ouyang_peng/article/details/50813419
前言
最近有個專案有關於播放音樂時候,關於歌詞有以下幾個功能:
1、實現歌詞同步滾動的功能,即歌曲播放到哪句歌詞,就高亮地顯示出正在播放的這個歌詞;
2、實現上下拖動歌詞時候,可以拖動播放器的進度。即可以不停地上下拖動歌詞,當手指離開螢幕時候 即從當前拖動到的歌詞位置播放。
3、實現歌詞的字型大小可以進行縮放的功能。即雙指在螢幕進行縮放操作時,歌詞的字型大小也進行相應的縮放操作。
下面我將這幾個功能做成一個demo來展示給大家。首先來看看這個demo的具體實現效果,如下面幾幅圖所示。
圖1、同步滾動歌詞
圖2、上下拖動歌詞1
圖3、上下拖動歌詞2
圖4、縮放歌詞
圖5、歌詞顯示(較大字型)
圖6、歌詞顯示(較小字型)
圖7、歌詞滾動時候,高亮地畫出正滾動到的歌詞內容以及歌詞的開始時間,並該句歌詞下面畫出一條直線
一、LRC歌詞檔案簡介
1、什麼是LRC歌詞檔案
lrc是英文lyric(歌詞)的縮寫,被用做歌詞檔案的副檔名。以lrc為副檔名的歌詞檔案可以在各類數碼播放器中同步顯示。
2、LRC歌詞檔案的格式
先來看一份標準的LRC歌詞檔案,下面展示的是王力巨集的《依然愛你》
的lrc歌詞的內容
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
LRC歌詞檔案的標籤型別
lrc歌詞文字中含有兩類標籤:一是標識標籤 ,二是時間標籤。
1、標識標籤
標識標籤,其格式為“[標識名:值]”,主要包含以下預定義的標籤:
- [ar:歌手名]
- [ti:歌曲名]
- [al:專輯名]
- [by:編輯者(指lrc歌詞的製作人)]
- [offset:時間補償值] (其單位是毫秒,正值表示整體提前,負值相反。這是用於總體調整顯示快慢的,但多數的MP3可能不會支援這種標籤)。
2、時間標籤
時間標籤,形式為“[mm:ss]”或“[mm:ss.ff]”(分鐘數:秒數.毫秒數),數字須為非負整數,
比如”[12:34.50]”是有效的,而”[0x0C:-34.50]”無效。
時間標籤需位於某行歌詞中的句首部分,一行歌詞可以包含多個時間標籤
(比如歌詞中的迭句部分)。當歌曲播放到達某一時間點時,MP3就會尋找對應的時間標籤並顯示標籤後面的歌詞文字,這樣就完成了“歌詞同步”的功能。
例如下面的這首 草蜢的《失戀戰線聯盟》,就是一行歌詞包含了多個時間標籤。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
[01:43.33][00:16.27]她總是隻留下電話號碼
上面這行歌詞表示:在 [00:16.27] 這個時間點播放 “她總是隻留下電話號碼” 這句歌詞,
在 [01:43.33] 這個時間點再一個播放 “她總是隻留下電話號碼” 這句歌詞。
其實可以把上面這行歌詞拆分為下面兩句歌詞:
[00:16.27]她總是隻留下電話號碼
[01:43.33]她總是隻留下電話號碼
二、解析LRC歌詞
1、讀取出歌詞檔案
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
例如:從assets目錄下讀取test.lrc歌詞檔案內容,則可以呼叫上面的getFromAssets(String fileName)方法得到歌詞的文字內容,如下所示:
- 1
2、解析得到的歌詞內容
1、表示每行歌詞內容的實體類LrcRow
首先封裝一個表示每行歌詞內容的實體類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表示該行歌詞的內容,如:當你我不小心又想起她
程式碼如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
該LrcRow的List createRows(String standardLrcLine)方法 ,將迴圈地一行一行的去讀取歌詞的內容。然後對每一行的歌詞進行解析,每解析出一個時間標籤[XX:XX.XX]則new出一個LrcRow物件,然後加入到歌詞行List集合中去。
該LrcRow類實現Comparable介面,用來進行解析之後的排序操作,排序按時間從小到大排序。
2、解析歌詞的構造器
ILrcBuilder介面
定義一個ILrcBuilder介面,介面有一個List getLrcRows(String rawLrc)方法,該方法用來解析歌詞,得到LrcRow的集合
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
DefaultLrcBuilder歌詞解析構造器
DefaultLrcBuilder實現ILrcBuilder介面,List getLrcRows(String rawLrc)方法會迴圈地讀取歌詞的每一行,然後呼叫LrcRow類的List createRows(String standardLrcLine)方法,得到解析每一行歌詞之後的LrcRow集合,再將每一行得到LrcRow集合中得到的LrcRow實體加入一個總 的到LrcRow集合rows中去,然後將rows集合根據歌詞行的時間排序,得到排序後的LrcRow集合,該集合就是最終的解析歌詞後的內容了。
程式碼如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
例如:通過下面程式碼來呼叫ILrcBuilder解析歌詞,
- 1
- 2
- 3
- 4
- 5
- 6
lrc歌詞原始內容
草蜢的《失戀戰線聯盟》,lrc原始內容如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
讀取該歌詞內容,過程中的列印日誌為: