已經(jīng)有兩個(gè)月時(shí)間沒(méi)有發(fā)表新文章了,從開(kāi)始發(fā)表文章以來(lái)阔挠,常常會(huì)有線上的"簡(jiǎn)友"通過(guò)QQ和微信與我進(jìn)行一些技術(shù)上溝通和交流飘庄,我也收獲良多,幾乎每次到最后购撼,我都會(huì)厚著臉皮說(shuō):"多多關(guān)注哦跪削,近期會(huì)有新文章要發(fā)表呢!"迂求。奈何碾盐,每一次當(dāng)我熱情高漲準(zhǔn)備在近期發(fā)表文章的時(shí)候,都因各種各樣的事情耽擱了揩局,于是乎毫玖,我一次又一次爽約了。的確凌盯,最近工作確實(shí)比較忙付枫,幾乎每一天都需要加班,難得某個(gè)周末的下午有點(diǎn)閑暇時(shí)間驰怎,我都泡在了球場(chǎng)上阐滩,熱愛(ài)籃球是其一,最重要的是做我們這行的县忌,由于工作性質(zhì)叶眉,每周一定的運(yùn)動(dòng)是非常必要的,身體是革命的本錢不是嘛芹枷! 不過(guò)衅疙,我可并沒(méi)有因?yàn)槊β稻蜁?huì)在閑暇時(shí)候放縱自己,我依然堅(jiān)持著自己的夢(mèng)想鸳慈,我一直在思考分享一些比較受用的功能效果饱溢,我也爭(zhēng)取把每一個(gè)Demo做到最好!
明天就是八月一號(hào)了走芋,想著要在八月第一天有一個(gè)良好的開(kāi)頭绩郎,也就寫(xiě)下了這篇文章潘鲫。
這次我要向大家分享的是一個(gè)歌詞控件,其實(shí)肋杖,也是我畢業(yè)設(shè)計(jì)中的一部分溉仑。起初我是用ScrollView嵌套TextView,再結(jié)合我的上一篇文章SpannableString來(lái)實(shí)現(xiàn)的状植,Demo其實(shí)我早早地就將放在github上浊竟,不知道有沒(méi)有朋友有留心看到,但是總感覺(jué)用著不是很流暢津畸,而且不容易加入一些自定義內(nèi)容振定,所以一直不好下筆,也不好向大家分享Demo肉拓。不過(guò)后频,有興趣的朋友可以看一下(下載地址),個(gè)人感覺(jué)還是挺有創(chuàng)意的暖途,嘻嘻1跋А(害羞臉~)。
效果圖是舊版本哦驻售,記住露久,是舊版本! 通過(guò)自定義View實(shí)現(xiàn)的"進(jìn)階版"LyricView功能更強(qiáng)大芋浮,體驗(yàn)效果更佳,能夠?qū)崿F(xiàn)歌詞滑動(dòng)查看壳快,當(dāng)前播放位置高亮顯示纸巷,滑動(dòng)到指定位置并播放等等,總的來(lái)說(shuō)眶痰,大致和網(wǎng)易云音樂(lè)的歌詞顯示效果一樣瘤旨。
考慮到歌詞顯示控件涉及到歌詞解析,自定義控件的實(shí)現(xiàn)等等諸多方面竖伯,可能文章的篇幅上會(huì)比較冗長(zhǎng)存哲,同時(shí)也為了方便"簡(jiǎn)友"們能夠根據(jù)自己的需求和愛(ài)好各取所需。我也就仿著我之前寫(xiě)的文章《像360懸浮窗那樣七婴,用WindowManager實(shí)現(xiàn)炫酷的懸浮迷你音樂(lè)盒》那樣祟偷,將"用自定義View實(shí)現(xiàn)歌詞顯示控件"這篇文章也分成上、下兩篇打厘,分別是《用自定義View實(shí)現(xiàn)歌詞顯示控件上篇之實(shí)現(xiàn)歌詞文件解析》和《用自定義View實(shí)現(xiàn)歌詞顯示控件下篇之自定義LyricView的實(shí)現(xiàn)》修肠。而今天將要分享的是上篇,主要講解關(guān)于*.lrc文件的解析户盯,內(nèi)容偏理論嵌施,所以本章最后我也不會(huì)附上Demo饲化,至于下篇我會(huì)盡快整理分享出來(lái),屆時(shí)上下篇的Demo我會(huì)整合在一起共享出來(lái)吗伤。好吧吃靠,進(jìn)入正題:
首先,了解歌詞文件的組成
寫(xiě)過(guò)音樂(lè)播放器的朋友也應(yīng)該都會(huì)去了解過(guò)歌詞文件的規(guī)范格式足淆,既然是歌詞顯示控件巢块,就必然需要好好了解歌詞文件的組成規(guī)范,才能準(zhǔn)確無(wú)誤的解析歌詞文件缸浦,獲得與我有用的信息夕冲。
[ti:一個(gè)人的北京]
[ar:好妹妹樂(lè)隊(duì)]
[al:南北]
[by:]
[offset:0]
[00:00.10]一個(gè)人的北京 - 好妹妹樂(lè)隊(duì)
[00:00.20]詞:秦昊
[00:00.30]曲:秦昊
[00:00.40]
[00:30.16]你有多久沒(méi)有看到 滿天的繁星
[00:37.34]城市夜晚虛偽的光明 遮住你的眼睛
[00:44.40]連周末的電影 也變得不再有趣
[00:51.71]疲憊的日子里 有太多的問(wèn)題
[00:59.21]
[01:00.96]你有多久單身一人 不再去旅行
[01:08.20]習(xí)慣下班回到家里 冷冰冰的空氣
[01:15.58]愛(ài)情這東西 你已經(jīng)不再有勇氣
[01:22.64]情歌有多動(dòng)聽(tīng) 你就有多懷疑
[01:30.60]許多人來(lái)來(lái)去去 相聚又別離
[01:38.29]也有人喝醉哭泣 在一個(gè)人的北京
[01:45.16]也許我成功失意 慢慢的老去
[01:52.76]能不能讓我留下片刻的回憶
[01:58.95]
[01:59.67]許多人來(lái)來(lái)去去 相聚又別離
[02:07.23]也有人匆匆逃離 這一個(gè)人的北京
[02:14.30]也許有一天我們 一起離開(kāi)這里
[02:21.86]離開(kāi)了這里 在晴朗的天氣
[02:28.38]
[02:58.98]你有多久單身一人 不再去旅行
[03:06.36]習(xí)慣下班回到家里 冷冰冰的空氣
[03:13.55]愛(ài)情這東西 你已經(jīng)不再有勇氣
[03:20.69]情歌有多動(dòng)聽(tīng) 你就有多懷疑
[03:28.53]許多人來(lái)來(lái)去去 相聚又別離
[03:36.22]也有人喝醉哭泣 在一個(gè)人的北京
[03:43.28]也許我成功失意 慢慢的老去
[03:50.82]能不能讓我留下片刻的回憶
[03:57.64]許多人來(lái)來(lái)去去 相聚又別離
[04:05.25]也有人匆匆逃離 這一個(gè)人的北京
[04:12.31]也許有一天我們 一起離開(kāi)這里
[04:19.88]離開(kāi)了這里 在晴朗的天氣
[04:26.62]許多人來(lái)來(lái)去去 相聚又別離
[04:34.24]也有人匆匆逃離 這一個(gè)人的北京
[04:41.37]也許有一天我們 一起離開(kāi)這里
[04:48.87]離開(kāi)了這里 在晴朗的天氣
[04:55.08]
[04:56.27]讓我擁抱你 在晴朗的天氣
這如上述文本顯示,是我在QQ音樂(lè)中下載的歌詞文件裂逐,并用文本方式打開(kāi)看到的一個(gè)結(jié)果歹鱼。其實(shí),所有歌詞文件(*.lrc)都是以一個(gè)標(biāo)準(zhǔn)來(lái)進(jìn)行制作的卜高,就如同上述文件一樣由以"[ti:"開(kāi)頭的標(biāo)題弥姻、以"[ar:"開(kāi)頭的歌手、以"[al:"開(kāi)頭的專輯掺涛、以"[by:"開(kāi)頭的制作庭敦、以"[offset:"開(kāi)頭的時(shí)間偏移量和以"[mm:ss.ms]"開(kāi)頭的歌詞信息組成,歌詞信息則是由開(kāi)始時(shí)間(分:秒.毫秒)和歌詞內(nèi)容兩部分組成薪缆。
接著秧廉,解析歌詞文件
既然了解了歌詞文件的組成部分,那么解析歌詞文件也就不是一件困難的事情了拣帽,就是簡(jiǎn)單的文件內(nèi)容讀忍鄣纭:首先獲取*.lrc歌詞文件的二進(jìn)制流InputStream,再又轉(zhuǎn)換成字符流(注意:轉(zhuǎn)化成字符流的時(shí)候需要選擇編碼减拭,經(jīng)過(guò)我多次嘗試蔽豺,發(fā)現(xiàn)好像QQ音樂(lè)的歌詞文件需要用"GBK"解碼,也不清楚會(huì)不會(huì)有具體的判別方式拧粪,有了解的朋友希望可以在留言區(qū)和大伙兒分享)修陡,然后再調(diào)用BufferedReader的readLine()方法逐行讀取文件內(nèi)容,就能獲得文件內(nèi)容了可霎,在這里有一點(diǎn)需要注意的是魄鸦,各種流在使用結(jié)束后一定要調(diào)用close()方法關(guān)閉。下面就是實(shí)現(xiàn)歌詞文件的解析工作:
首先癣朗,需要準(zhǔn)備兩個(gè)類主要用于歌詞解析結(jié)果的緩存:LyricInfo(歌詞信息:包含標(biāo)題号杏、歌手、專輯等等)和LineInfo(歌詞行信息:包含行開(kāi)始時(shí)間和歌詞行內(nèi)容):
LyricInfo 歌詞文件信息
class LyricInfo {
List<LineInfo> song_lines;
String song_artist; // 歌手
String song_title; // 標(biāo)題
String song_album; // 專輯
long song_offset; // 偏移量
}
LineInfo 歌詞行信息
class LineInfo {
String content; // 歌詞內(nèi)容
long start; // 開(kāi)始時(shí)間
}
解析歌詞文件源碼
/**
* 初始化歌詞信息
* @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();
}
}
}
/**
* 逐行解析歌詞內(nèi)容
* */
private void analyzeLyric(LyricInfo lyricInfo, String line) {
int index = line.lastIndexOf("]");
if(line != null && line.startsWith("[offset:")) {
// 時(shí)間偏移量
String string = line.substring(8, index).trim();
lyricInfo.song_offset = Long.parseLong(string);
return;
}
if(line != null && line.startsWith("[ti:")) {
// title 標(biāo)題
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) {
// 歌詞內(nèi)容
LineInfo lineInfo = new LineInfo();
lineInfo.content = line.substring(10, line.length());
lineInfo.start = measureStartTimeMillis(line.substring(0, 10));
lyricInfo.song_lines.add(lineInfo);
}
}
/**
* 從字符串中獲得時(shí)間值
* */
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;
}
最后,驗(yàn)證解析效果
完成歌詞解析盾致,接下來(lái)就是驗(yàn)證歌詞解析的一個(gè)實(shí)際效果的時(shí)候了:
File file = new File(Constant.lyricPath + "一個(gè)人的北京 - 好妹妹樂(lè)隊(duì).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();
}
}
關(guān)于歌詞解析的內(nèi)容到這里就結(jié)束了主经,希望大家能夠多多關(guān)注哦!
作者申明:如果文中有表述不當(dāng)或闡述錯(cuò)誤的地方庭惜,還望正在看文章的您可以幫忙指出罩驻,有疑惑也可以在評(píng)論區(qū)提問(wèn)或者私信,期待您的意見(jiàn)和建議护赊,歡迎關(guān)注交流惠遏。