自定義View強勢來襲,用自定義View實現歌詞顯示控件上篇之實現歌詞文件解析
這次我要向大家分享的是一個歌詞控件,其實,也是我畢業設計中的一部分。起初我是用ScrollView嵌套TextView,再結合我的上一篇文章SpannableString來實現的,Demo其實我早早地就將放在github上,不知道有沒有朋友有留心看到,但是總感覺用著不是很流暢,而且不容易加入一些自定義內容,所以一直不好下筆,也不好向大家分享Demo。不過,有興趣的朋友可以看一下 (下載地址) ,個人感覺還是挺有創意的,嘻嘻!(害羞臉~)。
用ScrollView嵌套TextView實現LyricView效果圖
效果圖是舊版本哦,記住,是舊版本! 通過自定義View實現的"進階版"LyricView功能更強大,體驗效果更佳,能夠實現歌詞滑動查看,當前播放位置高亮顯示,滑動到指定位置并播放等等,總的來說,大致和網易云音樂的歌詞顯示效果一樣。
考慮到歌詞顯示控件涉及到歌詞解析,自定義控件的實現等等諸多方面,可能文章的篇幅上會比較冗長,同時也為了方便"簡友"們能夠根據自己的需求和愛好各取所需。我也就仿著我之前寫的文章 《像360懸浮窗那樣,用WindowManager實現炫酷的懸浮迷你音樂盒》 那樣,將"用自定義View實現歌詞顯示控件"這篇文章也分成上、下兩篇,分別是 《用自定義View實現歌詞顯示控件上篇之實現歌詞文件解析》 和《用自定義View實現歌詞顯示控件下篇之自定義LyricView的實現》。而今天將要分享的是上篇,主要講解關于*.lrc文件的解析,內容偏理論,所以本章最后我也不會附上Demo,至于下篇我會盡快整理分享出來,屆時上下篇的Demo我會整合在一起共享出來。好吧,進入正題:
首先,了解歌詞文件的組成
寫過音樂播放器的朋友也應該都會去了解過歌詞文件的規范格式,既然是歌詞顯示控件,就必然需要好好了解歌詞文件的組成規范,才能準確無誤的解析歌詞文件,獲得與我有用的信息。
[ti:一個人的北京] [ar:好妹妹樂隊] [al:南北] [by:] [offset:0] [00:00.10]一個人的北京 - 好妹妹樂隊 [00:00.20]詞:秦昊 [00:00.30]曲:秦昊 [00:00.40] [00:30.16]你有多久沒有看到 滿天的繁星 [00:37.34]城市夜晚虛偽的光明 遮住你的眼睛 [00:44.40]連周末的電影 也變得不再有趣 [00:51.71]疲憊的日子里 有太多的問題 [00:59.21] [01:00.96]你有多久單身一人 不再去旅行 [01:08.20]習慣下班回到家里 冷冰冰的空氣 [01:15.58]愛情這東西 你已經不再有勇氣 [01:22.64]情歌有多動聽 你就有多懷疑 [01:30.60]許多人來來去去 相聚又別離 [01:38.29]也有人喝醉哭泣 在一個人的北京 [01:45.16]也許我成功失意 慢慢的老去 [01:52.76]能不能讓我留下片刻的回憶 [01:58.95] [01:59.67]許多人來來去去 相聚又別離 [02:07.23]也有人匆匆逃離 這一個人的北京 [02:14.30]也許有一天我們 一起離開這里 [02:21.86]離開了這里 在晴朗的天氣 [02:28.38] [02:58.98]你有多久單身一人 不再去旅行 [03:06.36]習慣下班回到家里 冷冰冰的空氣 [03:13.55]愛情這東西 你已經不再有勇氣 [03:20.69]情歌有多動聽 你就有多懷疑 [03:28.53]許多人來來去去 相聚又別離 [03:36.22]也有人喝醉哭泣 在一個人的北京 [03:43.28]也許我成功失意 慢慢的老去 [03:50.82]能不能讓我留下片刻的回憶 [03:57.64]許多人來來去去 相聚又別離 [04:05.25]也有人匆匆逃離 這一個人的北京 [04:12.31]也許有一天我們 一起離開這里 [04:19.88]離開了這里 在晴朗的天氣 [04:26.62]許多人來來去去 相聚又別離 [04:34.24]也有人匆匆逃離 這一個人的北京 [04:41.37]也許有一天我們 一起離開這里 [04:48.87]離開了這里 在晴朗的天氣 [04:55.08] [04:56.27]讓我擁抱你 在晴朗的天氣
這如上述文本顯示,是我在QQ音樂中下載的歌詞文件,并用文本方式打開看到的一個結果。其實,所有歌詞文件(*.lrc)都是以一個標準來進行制作的,就如同上述文件一樣由以"[ti:"開頭的標題、以"[ar:"開頭的歌手、以"[al:"開頭的專輯、以"[by:"開頭的制作、以"[offset:"開頭的時間偏移量和以"[mm:ss.ms]"開頭的歌詞信息組成,歌詞信息則是由開始時間(分:秒.毫秒)和歌詞內容兩部分組成。
接著,解析歌詞文件
既然了解了歌詞文件的組成部分,那么解析歌詞文件也就不是一件困難的事情了,就是簡單的文件內容讀取:首先獲取*.lrc歌詞文件的二進制流InputStream,再又轉換成字符流(注意:轉化成字符流的時候需要選擇編碼,經過我多次嘗試,發現好像QQ音樂的歌詞文件需要用"GBK"解碼,也不清楚會不會有具體的判別方式,有了解的朋友希望可以在留言區和大伙兒分享),然后再調用BufferedReader的readLine()方法逐行讀取文件內容,就能獲得文件內容了,在這里有一點需要注意的是,各種流在使用結束后一定要調用close()方法關閉。下面就是實現歌詞文件的解析工作:
首先,需要準備兩個類主要用于歌詞解析結果的緩存:LyricInfo(歌詞信息:包含標題、歌手、專輯等等)和LineInfo(歌詞行信息:包含行開始時間和歌詞行內容):
LyricInfo 歌詞文件信息
class LyricInfo { List<LineInfo> song_lines; String song_artist; // 歌手 String song_title; // 標題 String song_album; // 專輯 long song_offset; // 偏移量 }
LineInfo 歌詞行信息
class LineInfo { String content; // 歌詞內容 long start; // 開始時間 }
解析歌詞文件源碼
/** * 初始化歌詞信息 * @param inputStream 歌詞文件的流信息 * */ private void setupLyricResource(InputStream inputStream, String charsetName) { if(inputStream != null) { try { LyricInfo lyricInfo = new LyricInfo(); lyricInfo.song_lines = new ArrayList<>(); InputStreamReader inputStreamReader = new InputStreamReader(inputStream, charsetName); BufferedReader reader = new BufferedReader(inputStreamReader); String line = null; while((line = reader.readLine()) != null) { analyzeLyric(lyricInfo, line); } reader.close(); inputStream.close(); inputStreamReader.close(); } catch (IOException e) { e.printStackTrace(); } } } /** * 逐行解析歌詞內容 * */ private void analyzeLyric(LyricInfo lyricInfo, String line) { int index = line.lastIndexOf("]"); if(line != null && line.startsWith("[offset:")) { // 時間偏移量 String string = line.substring(8, index).trim(); lyricInfo.song_offset = Long.parseLong(string); return; } if(line != null && line.startsWith("[ti:")) { // title 標題 String string = line.substring(4, index).trim(); lyricInfo.song_title = string; return; } if(line != null && line.startsWith("[ar:")) { // artist 作者 String string = line.substring(4, index).trim(); lyricInfo.song_artist = string; return; } if(line != null && line.startsWith("[al:")) { // album 所屬專輯 String string = line.substring(4, index).trim(); lyricInfo.song_album = string; return; } if(line != null && line.startsWith("[by:")) { return; } if(line != null && index == 9 && line.trim().length() > 10) { // 歌詞內容 LineInfo lineInfo = new LineInfo(); lineInfo.content = line.substring(10, line.length()); lineInfo.start = measureStartTimeMillis(line.substring(0, 10)); lyricInfo.song_lines.add(lineInfo); } } /** * 從字符串中獲得時間值 * */ private long measureStartTimeMillis(String str) { long minute = Long.parseLong(str.substring(1, 3)); long second = Long.parseLong(str.substring(4, 6)); long millisecond = Long.parseLong(str.substring(7, 9)); return millisecond + second * 1000 + minute * 60 * 1000; }
最后,驗證解析效果
完成歌詞解析,接下來就是驗證歌詞解析的一個實際效果的時候了:
File file = new File(Constant.lyricPath + "一個人的北京 - 好妹妹樂隊.lrc"); if (file != null && file.exists()) { try { setupLyricResource(new FileInputStream(file), "GBK"); StringBuffer stringBuffer = new StringBuffer(); if(lyricInfo != null && lyricInfo.song_lines != null) { int size = lyricInfo.song_lines.size(); for (int i = 0; i < size; i ++) { stringBuffer.append(lyricInfo.song_lines.get(i).content + "\n"); } textView.setText(stringBuffer.toString()); } } catch (FileNotFoundException e) { e.printStackTrace(); } }
歌詞解析效果圖
關于歌詞解析的內容到這里就結束了。
來自:http://www.jianshu.com/p/7b6a42deff27