我的Android進階之旅------>Android自定義View來實現解析lrc歌詞並同步滾動、上下拖動、縮放歌詞的功能
前言
最近有個專案有關於播放音樂時候,關於歌詞有以下幾個功能:
1、實現歌詞同步滾動的功能,即歌曲播放到哪句歌詞,就高亮地顯示出正在播放的這個歌詞;
2、實現上下拖動歌詞時候,可以拖動播放器的進度。即可以不停地上下拖動歌詞,當手指離開螢幕時候 即從當前拖動到的歌詞位置播放。
3、實現歌詞的字型大小可以進行縮放的功能。即雙指在螢幕進行縮放操作時,歌詞的字型大小也進行相應的縮放操作。
下面我將這幾個功能做成一個demo來展示給大家。首先來看看這個demo的具體實現效果,如下面幾幅圖所示。
圖1、同步滾動歌詞
圖2、上下拖動歌詞1
圖3、上下拖動歌詞2
圖4、縮放歌詞
圖5、歌詞顯示(較大字型)
圖6、歌詞顯示(較小字型)
圖7、歌詞滾動時候,高亮地畫出正滾動到的歌詞內容以及歌詞的開始時間,並該句歌詞下面畫出一條直線
一、LRC歌詞檔案簡介
1、什麼是LRC歌詞檔案
lrc是英文lyric(歌詞)的縮寫,被用做歌詞檔案的副檔名。以lrc為副檔名的歌詞檔案可以在各類數碼播放器中同步顯示。
2、LRC歌詞檔案的格式
先來看一份標準的LRC歌詞檔案,下面展示的是王力巨集的《依然愛你》的lrc歌詞的內容
[ti:依然愛你]
[ar:王力巨集]
[al:火力全開 新歌+精選]
[by:歐陽鵬]
[00:01.17]一閃一閃亮晶晶 留下歲月的痕跡
[00:07.29]我的世界的重心 依然還是你
[00:13.37]一年一年又一年 飛逝盡在一轉眼
[00:20.29]唯一永遠不改變 是不停的改變
[00:27.14]我不像從前的自己 你也有點不像你
[00:33.36]但在我眼中你的笑 依然的美麗
[00:39.53]這次只能往前走 一個方向順時鐘
[00:46.12]不知道還要多久 所以要讓你懂
[00:51.82]我依然愛你 就是唯一的退路
[00:57.36]我依然珍惜 時時刻刻的幸福
[01:04.65]你每個呼吸 每個動作 每個表情
[01:11.43] 到最後一定會依然愛你
[01:18.08]依然愛你 依然愛你
[01:25.58]我不像從前的自己 你也有點不像你
[01:31.52]但在我眼中你的笑 依然的美麗
[01:37.61]這次只能往前走 一個方向順時鐘
[01:44.42]不知道還要多久 所以要讓你懂
[01:50.18]我依然愛你 就是唯一的退路
[01:55.65]我依然珍惜 時時刻刻的幸福
[02:02.84]你每個呼吸 每個動作 每個表情
[02:09.77]到最後一定會依然愛你
[02:15.61]
[02:17.61]lrc製作:http://blog.csdn.net/ouyang_peng 歐陽鵬
[02:25.61]
[02:31.06]依然愛你 依然愛你
[02:36.63]
[02:42.32]我依然愛你 或許是命中註定
[02:47.70]多年之後 任何人都無法代替
[02:54.57]那些時光 是我這一輩子 最美好
[03:01.84]那些回憶 依然無法忘記
[03:07.88]我依然愛你 就是唯一的退路
[03:13.95]我依然珍惜 時時刻刻的幸福
[03:21.32]你每個呼吸 每個動作 每個表情
[03:28.20]到最後一定會依然愛你
[03:34.76]你每個呼吸 每個動作 每個表情
[03:42.04]到永遠一定會依然愛你
[03:53.28]
[04:01.28]
LRC歌詞檔案的標籤型別
lrc歌詞文字中含有兩類標籤:一是標識標籤 ,二是時間標籤。
1、標識標籤
標識標籤,其格式為“[標識名:值]”,主要包含以下預定義的標籤:
- [ar:歌手名]
- [ti:歌曲名]
- [al:專輯名]
- [by:編輯者(指lrc歌詞的製作人)]
- [offset:時間補償值] (其單位是毫秒,正值表示整體提前,負值相反。這是用於總體調整顯示快慢的,但多數的MP3可能不會支援這種標籤)。
2、時間標籤
時間標籤,形式為“[mm:ss]”或“[mm:ss.ff]”(分鐘數:秒數.毫秒數),數字須為非負整數,
比如”[12:34.50]”是有效的,而”[0x0C:-34.50]”無效。
時間標籤需位於某行歌詞中的句首部分,一行歌詞可以包含多個時間標籤
(比如歌詞中的迭句部分)。當歌曲播放到達某一時間點時,MP3就會尋找對應的時間標籤並顯示標籤後面的歌詞文字,這樣就完成了“歌詞同步”的功能。
例如下面的這首 草蜢的《失戀戰線聯盟》,就是一行歌詞包含了多個時間標籤。
[ti:失戀戰線聯盟]
[ar:草蜢]
[al:]
[00:00.00]草蜢-失戀戰線聯盟
[00:08.78]編輯:小婧
[01:43.33][00:16.27]她總是隻留下電話號碼
[01:46.97][00:19.81]從不肯讓我送她回家
[01:50.61][00:23.43]聽說你也曾經愛上過她
[01:54.15][00:27.07]曾經也同樣無法自拔
[01:57.78][00:30.72]你說你學不會假裝瀟灑
[02:01.41][00:34.36]卻叫我別太早放棄她
[02:05.05][00:37.99]把過去傳說成一段神話
[02:08.70][00:41.59]然後笑你是一樣的傻
[02:12.01][00:45.11]我們那麼在乎她
[02:14.15][00:47.01]卻被她全部抹殺
[02:15.96][00:48.87]越談她越相信永遠得不到回答
[02:19.57][00:52.49]到底她怎麼想
[02:21.35][00:54.28]應該繼續在這麼
[02:23.37][00:56.36]還是說穿跑了吧
[02:26.89][00:59.80]找一個承認失戀的方法
[02:30.48][01:03.41]讓心情好好地放個假
[02:34.14][01:07.00]當你我不小心又想起她
[02:45.69][02:42.20][02:37.69][01:10.60]就在記憶裡畫一個叉
[02:48.69]
[01:33.58]編輯:小婧
[01:43.33][00:16.27]她總是隻留下電話號碼
上面這行歌詞表示:在 [00:16.27] 這個時間點播放 “她總是隻留下電話號碼” 這句歌詞,
在 [01:43.33] 這個時間點再一個播放 “她總是隻留下電話號碼” 這句歌詞。
其實可以把上面這行歌詞拆分為下面兩句歌詞:
[00:16.27]她總是隻留下電話號碼
[01:43.33]她總是隻留下電話號碼
二、解析LRC歌詞
1、讀取出歌詞檔案
/**
* 從assets目錄下讀取歌詞檔案內容
* @param fileName
* @return
*/
public String getFromAssets(String fileName){
try {
InputStreamReader inputReader = new InputStreamReader( getResources().getAssets().open(fileName) );
BufferedReader bufReader = new BufferedReader(inputReader);
String line="";
String result="";
while((line = bufReader.readLine()) != null){
if(line.trim().equals(""))
continue;
result += line + "\r\n";
}
return result;
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
例如:從assets目錄下讀取test.lrc歌詞檔案內容,則可以呼叫上面的getFromAssets(String fileName)方法得到歌詞的文字內容,如下所示:
String lrc = getFromAssets("test.lrc");
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表示該行歌詞的內容,如:當你我不小心又想起她
程式碼如下:
package com.oyp.lrc.view.impl;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
/**
* 歌詞行
* 包括該行歌詞的時間,歌詞內容
*/
public class LrcRow implements Comparable<LrcRow>{
public final static String TAG = "LrcRow";
/** 該行歌詞要開始播放的時間,格式如下:[02:34.14] */
public String strTime;
/** 該行歌詞要開始播放的時間,由[02:34.14]格式轉換為long型,
* 即將2分34秒14毫秒都轉為毫秒後 得到的long型值:time=02*60*1000+34*1000+14
*/
public long time;
/** 該行歌詞的內容 */
public String content;
public LrcRow(){}
public LrcRow(String strTime,long time,String content){
this.strTime = strTime;
this.time = time;
this.content = content;
// Log.d(TAG,"strTime:" + strTime + " time:" + time + " content:" + content);
}
@Override
public String toString() {
return "[" + strTime + " ]" + content;
}
/**
* 讀取歌詞的每一行內容,轉換為LrcRow,加入到集合中
*/
public static List<LrcRow> createRows(String standardLrcLine){
/**
一行歌詞只有一個時間的 例如:徐佳瑩 《我好想你》
[01:15.33]我好想你 好想你
一行歌詞有多個時間的 例如:草蜢 《失戀戰線聯盟》
[02:34.14][01:07.00]當你我不小心又想起她
[02:45.69][02:42.20][02:37.69][01:10.60]就在記憶裡畫一個叉
**/
try{
if(standardLrcLine.indexOf("[") != 0 || standardLrcLine.indexOf("]") != 9 ){
return null;
}
//[02:34.14][01:07.00]當你我不小心又想起她
//找到最後一個 ‘]’ 的位置
int lastIndexOfRightBracket = standardLrcLine.lastIndexOf("]");
//歌詞內容就是 ‘]’ 的位置之後的文字 eg: 當你我不小心又想起她
String content = standardLrcLine.substring(lastIndexOfRightBracket + 1, standardLrcLine.length());
//歌詞時間就是 ‘]’ 的位置之前的文字 eg: [02:34.14][01:07.00]
/**
將時間格式轉換一下 [mm:ss.SS][mm:ss.SS] 轉換為 -mm:ss.SS--mm:ss.SS-
即:[02:34.14][01:07.00] 轉換為 -02:34.14--01:07.00-
*/
String times = standardLrcLine.substring(0,lastIndexOfRightBracket + 1).replace("[", "-").replace("]", "-");
//通過 ‘-’ 來拆分字串
String arrTimes[] = times.split("-");
List<LrcRow> listTimes = new ArrayList<LrcRow>();
for(String temp : arrTimes){
if(temp.trim().length() == 0){
continue;
}
/** [02:34.14][01:07.00]當你我不小心又想起她
*
上面的歌詞的就可以拆分為下面兩句歌詞了
[02:34.14]當你我不小心又想起她
[01:07.00]當你我不小心又想起她
*/
LrcRow lrcRow = new LrcRow(temp, timeConvert(temp), content);
listTimes.add(lrcRow);
}
return listTimes;
}catch(Exception e){
Log.e(TAG,"createRows exception:" + e.getMessage());
return null;
}
}
/**
* 將解析得到的表示時間的字元轉化為Long型
*/
private static long timeConvert(String timeString){
//因為給如的字串的時間格式為XX:XX.XX,返回的long要求是以毫秒為單位
//將字串 XX:XX.XX 轉換為 XX:XX:XX
timeString = timeString.replace('.', ':');
//將字串 XX:XX:XX 拆分
String[] times = timeString.split(":");
// mm:ss:SS
return Integer.valueOf(times[0]) * 60 * 1000 +//分
Integer.valueOf(times[1]) * 1000 +//秒
Integer.valueOf(times[2]) ;//毫秒
}
/**
* 排序的時候,根據歌詞的時間來排序
*/
public int compareTo(LrcRow another) {
return (int)(this.time - another.time);
}
}
該LrcRow的List createRows(String standardLrcLine)方法 ,將迴圈地一行一行的去讀取歌詞的內容。然後對每一行的歌詞進行解析,每解析出一個時間標籤[XX:XX.XX]則new出一個LrcRow物件,然後加入到歌詞行List集合中去。
該LrcRow類實現Comparable介面,用來進行解析之後的排序操作,排序按時間從小到大排序。
2、解析歌詞的構造器
ILrcBuilder介面
定義一個ILrcBuilder介面,介面有一個List getLrcRows(String rawLrc)方法,該方法用來解析歌詞,得到LrcRow的集合
package com.oyp.lrc.view;
import com.oyp.lrc.view.impl.LrcRow;
import java.util.List;
/**
* 解析歌詞,得到LrcRow的集合
*/
public interface ILrcBuilder {
List<LrcRow> getLrcRows(String rawLrc);
}
DefaultLrcBuilder歌詞解析構造器
DefaultLrcBuilder實現ILrcBuilder介面,List getLrcRows(String rawLrc)方法會迴圈地讀取歌詞的每一行,然後呼叫LrcRow類的List createRows(String standardLrcLine)方法,得到解析每一行歌詞之後的LrcRow集合,再將每一行得到LrcRow集合中得到的LrcRow實體加入一個總 的到LrcRow集合rows中去,然後將rows集合根據歌詞行的時間排序,得到排序後的LrcRow集合,該集合就是最終的解析歌詞後的內容了。
程式碼如下:
package com.oyp.lrc.view.impl;
import android.util.Log;
import com.oyp.lrc.view.ILrcBuilder;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* 解析歌詞,得到LrcRow的集合
*/
public class DefaultLrcBuilder implements ILrcBuilder {
static final String TAG = "DefaultLrcBuilder";
public List<LrcRow> getLrcRows(String rawLrc) {
Log.d(TAG,"getLrcRows by rawString");
if(rawLrc == null || rawLrc.length() == 0){
Log.e(TAG,"getLrcRows rawLrc null or empty");
return null;
}
StringReader reader = new StringReader(rawLrc);
BufferedReader br = new BufferedReader(reader);
String line = null;
List<LrcRow> rows = new ArrayList<LrcRow>();
try{
//迴圈地讀取歌詞的每一行
do{
line = br.readLine();
/**
一行歌詞只有一個時間的 例如:徐佳瑩 《我好想你》
[01:15.33]我好想你 好想你
一行歌詞有多個時間的 例如:草蜢 《失戀戰線聯盟》
[02:34.14][01:07.00]當你我不小心又想起她
[02:45.69][02:42.20][02:37.69][01:10.60]就在記憶裡畫一個叉
**/
Log.d(TAG,"lrc raw line: " + line);
if(line != null && line.length() > 0){
//解析每一行歌詞 得到每行歌詞的集合,因為有些歌詞重複有多個時間,就可以解析出多個歌詞行來
List<LrcRow> lrcRows = LrcRow.createRows(line);
if(lrcRows != null && lrcRows.size() > 0){
for(LrcRow row : lrcRows){
rows.add(row);
}
}
}
}while(line != null);
if( rows.size() > 0 ){
// 根據歌詞行的時間排序
Collections.sort(rows);
if(rows!=null&&rows.size()>0){
for(LrcRow lrcRow:rows){
Log.d(TAG, "lrcRow:" + lrcRow.toString());
}
}
}
}catch(Exception e){
Log.e(TAG,"parse exceptioned:" + e.getMessage());
return null;
}finally{
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
reader.close();
}
return rows;
}
}
例如:通過下面程式碼來呼叫ILrcBuilder解析歌詞,
//從assets目錄下讀取歌詞檔案內容
String lrc = getFromAssets("test.lrc");
//解析歌詞構造器
ILrcBuilder builder = new DefaultLrcBuilder();
//解析歌詞返回LrcRow集合
List<LrcRow> rows = builder.getLrcRows(lrc);
lrc歌詞原始內容
草蜢的《失戀戰線聯盟》,lrc原始內容如下:
[ti:失戀戰線聯盟]
[ar:草蜢]
[al:]
[00:00.00]草蜢-失戀戰線聯盟
[00:08.78]編輯:小婧
[01:43.33][00:16.27]她總是隻留下電話號碼
[01:46.97][00:19.81]從不肯讓我送她回家
[01:50.61][00:23.43]聽說你也曾經愛上過她
[01:54.15][00:27.07]曾經也同樣無法自拔
[01:57.78][00:30.72]你說你學不會假裝瀟灑
[02:01.41][00:34.36]卻叫我別太早放棄她
[02:05.05][00:37.99]把過去傳說成一段神話
[02:08.70][00:41.59]然後笑你是一樣的傻
[02:12.01][00:45.11]我們那麼在乎她
[02:14.15][00:47.01]卻被她全部抹殺
[02:15.96][00:48.87]越談她越相信永遠得不到回答
[02:19.57][00:52.49]到底她怎麼想
[02:21.35][00:54.28]應該繼續在這麼
[02:23.37][00:56.36]還是說穿跑了吧
[02:26.89][00:59.80]找一個承認失戀的方法
[02:30.48][01:03.41]讓心情好好地放個假
[02:34.14][01:07.00]當你我不小心又想起她
[02:45.69][02:42.20][02:37.69][01:10.60]就在記憶裡畫一個叉
[02:48.69]
[01:33.58]編輯:小婧
讀取該歌詞內容,過程中的列印日誌為:
03-06 00:41:15.352 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrc raw line: [ti:失戀戰線聯盟]
03-06 00:41:15.352 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrc raw line: [ar:草蜢]
03-06 00:41:15.352 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrc raw line: [al:]
03-06 00:41:15.352 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrc raw line: [00:00.00]草蜢-失戀戰線聯盟
03-06 00:41:15.352 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrc raw line: [00:08.78]編輯:小婧
03-06 00:41:15.352 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrc raw line: [01:43.33][00:16.27]她總是隻留下電話號碼
03-06 00:41:15.352 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrc raw line: [01:46.97][00:19.81]從不肯讓我送她回家
03-06 00:41:15.352 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrc raw line: [01:50.61][00:23.43]聽說你也曾經愛上過她
03-06 00:41:15.352 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrc raw line: [01:54.15][00:27.07]曾經也同樣無法自拔
03-06 00:41:15.352 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrc raw line: [01:57.78][00:30.72]你說你學不會假裝瀟灑
03-06 00:41:15.352 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrc raw line: [02:01.41][00:34.36]卻叫我別太早放棄她
03-06 00:41:15.362 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrc raw line: [02:05.05][00:37.99]把過去傳說成一段神話
03-06 00:41:15.362 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrc raw line: [02:08.70][00:41.59]然後笑你是一樣的傻
03-06 00:41:15.362 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrc raw line: [02:12.01][00:45.11]我們那麼在乎她
03-06 00:41:15.362 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrc raw line: [02:14.15][00:47.01]卻被她全部抹殺
03-06 00:41:15.362 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrc raw line: [02:15.96][00:48.87]越談她越相信永遠得不到回答
03-06 00:41:15.362 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrc raw line: [02:19.57][00:52.49]到底她怎麼想
03-06 00:41:15.362 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrc raw line: [02:21.35][00:54.28]應該繼續在這麼
03-06 00:41:15.362 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrc raw line: [02:23.37][00:56.36]還是說穿跑了吧
03-06 00:41:15.362 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrc raw line: [02:26.89][00:59.80]找一個承認失戀的方法
03-06 00:41:15.362 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrc raw line: [02:30.48][01:03.41]讓心情好好地放個假
03-06 00:41:15.362 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrc raw line: [02:34.14][01:07.00]當你我不小心又想起她
03-06 00:41:15.362 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrc raw line: [02:45.69][02:42.20][02:37.69][01:10.60]就在記憶裡畫一個叉
03-06 00:41:15.362 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrc raw line: [02:48.69]
03-06 00:41:15.362 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrc raw line: [01:33.58]編輯:小婧
03-06 00:41:15.362 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrc raw line: null
解析歌詞後遍歷List<LrcRow>集合的列印日誌為:
03-06 00:41:15.372 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrcRow:[00:00.00 ]草蜢-失戀戰線聯盟
03-06 00:41:15.372 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrcRow:[00:08.78 ]編輯:小婧
03-06 00:41:15.372 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrcRow:[00:16.27 ]她總是隻留下電話號碼
03-06 00:41:15.372 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrcRow:[00:19.81 ]從不肯讓我送她回家
03-06 00:41:15.372 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrcRow:[00:23.43 ]聽說你也曾經愛上過她
03-06 00:41:15.372 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrcRow:[00:27.07 ]曾經也同樣無法自拔
03-06 00:41:15.372 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrcRow:[00:30.72 ]你說你學不會假裝瀟灑
03-06 00:41:15.372 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrcRow:[00:34.36 ]卻叫我別太早放棄她
03-06 00:41:15.372 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrcRow:[00:37.99 ]把過去傳說成一段神話
03-06 00:41:15.372 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrcRow:[00:41.59 ]然後笑你是一樣的傻
03-06 00:41:15.372 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrcRow:[00:45.11 ]我們那麼在乎她
03-06 00:41:15.372 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrcRow:[00:47.01 ]卻被她全部抹殺
03-06 00:41:15.372 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrcRow:[00:48.87 ]越談她越相信永遠得不到回答
03-06 00:41:15.372 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrcRow:[00:52.49 ]到底她怎麼想
03-06 00:41:15.372 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrcRow:[00:54.28 ]應該繼續在這麼
03-06 00:41:15.372 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrcRow:[00:56.36 ]還是說穿跑了吧
03-06 00:41:15.372 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrcRow:[00:59.80 ]找一個承認失戀的方法
03-06 00:41:15.372 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrcRow:[01:03.41 ]讓心情好好地放個假
03-06 00:41:15.372 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrcRow:[01:07.00 ]當你我不小心又想起她
03-06 00:41:15.372 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrcRow:[01:10.60 ]就在記憶裡畫一個叉
03-06 00:41:15.372 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrcRow:[01:33.58 ]編輯:小婧
03-06 00:41:15.372 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrcRow:[01:43.33 ]她總是隻留下電話號碼
03-06 00:41:15.372 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrcRow:[01:46.97 ]從不肯讓我送她回家
03-06 00:41:15.372 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrcRow:[01:50.61 ]聽說你也曾經愛上過她
03-06 00:41:15.372 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrcRow:[01:54.15 ]曾經也同樣無法自拔
03-06 00:41:15.382 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrcRow:[01:57.78 ]你說你學不會假裝瀟灑
03-06 00:41:15.382 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrcRow:[02:01.41 ]卻叫我別太早放棄她
03-06 00:41:15.382 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrcRow:[02:05.05 ]把過去傳說成一段神話
03-06 00:41:15.382 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrcRow:[02:08.70 ]然後笑你是一樣的傻
03-06 00:41:15.382 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrcRow:[02:12.01 ]我們那麼在乎她
03-06 00:41:15.382 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrcRow:[02:14.15 ]卻被她全部抹殺
03-06 00:41:15.382 5265-5265/com.oyp.lrc D/DefaultLrcBuilder: lrcRow:[02:15.96 ]越談她越相信永遠得不到回答
相關推薦
【我的Android進階之旅】自定義ContentProvider
引言
我們知道Android有四大元件,ContentProvider是其中之一,顧名思義:內容提供者。什麼是內容提供者呢?一個抽象類,可以暴露應用的資料給其他應用。應用裡的資料通常說的是資料庫,事實上普通的檔案,甚至是記憶體中的物件,也可以作為內容提供者暴露的
【我的Android進階之旅】自定義控制元件之使用ViewPager實現可以預覽的畫廊效果,並且自定義畫面切換的動畫效果的切換時間
我們來看下效果
在這裡,我們實現的是,一個ViewPager來顯示圖片列表。這裡一個頁面,ViewPage展示了前後的預覽,我們讓預覽頁進行Y軸的壓縮,並設定透明度為0.5f,所有我們看到gif最後,左右兩邊的圖片有點朦朧感。讓預覽頁和主頁面有主從感。我們用分
我的Android進階之旅------>Android自定義View來實現解析lrc歌詞並同步滾動、上下拖動、縮放歌詞的功能
前言
最近有個專案有關於播放音樂時候,關於歌詞有以下幾個功能:
1、實現歌詞同步滾動的功能,即歌曲播放到哪句歌詞,就高亮地顯示出正在播放的這個歌詞;
2、實現上下拖動歌詞時候,可以拖動播放器的進度。即可以不停地上下拖動歌詞,
Android自定義View來實現解析lrc歌詞同步滾動、上下拖動、縮放歌詞等功能
http://blog.csdn.net/ouyang_peng/article/details/50813419
前言
最近有個專案有關於播放音樂時候,關於歌詞有以下幾個功能:
1、實現歌詞同步滾動的功能,即歌曲播放到哪句
我的Android進階之旅------>Android如何通過自定義SeekBar來實現視訊播放進度條
首先來看一下效果圖,如下所示:其中進度條如下:接下來說一說我的思路,上面的進度拖動條有自定義的Thumb,在Thumb正上方有一個PopupWindow視窗,窗口裡面顯示當前的播放時間。在SeekBar右邊有一個文字框顯示當前播放時間/總時間。step1、先來看一看Popup
我的Android進階之旅------>Android自定義View實現帶數字的進度條(NumberProgressBar)
今天在Github上面看到一個來自於 daimajia所寫的關於Android自定義View實現帶數字的進度條(NumberProgressBar)的精彩案例,在這裡分享給大家一起來學習學習!同時感謝daimajia的開源奉獻!
第一步、效果展
我的Android進階之旅------>android中一些特殊字元(如:←↑→↓等箭頭符號)的Unicode碼值
在專案中,有時候在一些控制元件(如Button、TextView)中要新增一些符號,如下圖所示: 這個時候可以使用圖片的方式來顯示,不過這些
我的Android進階之旅------>Android 關於arm64-v8a、armeabi-v7a、armeabi、x86下的so檔案相容問題
Android 裝置的CPU型別(通常稱為”ABIs”)
armeabiv-v7a: 第7代及以上的 ARM 處理器。2011年15月以後的生產的大部分Android裝置都使用它.
arm64-v8a: 第8代、64位ARM處理器,很少裝置,三星 Ga
我的Android進階之旅------>Android中高低API版本相容使用@TargetApi或者@SuppressLint("NewApi")
Android中高低API版本相容使用@TargetApi或者@SuppressLint("NewApi")
例如:AndroidManifest.xml中,我們配置了sdk版本的最低為9,目標sdk
我的Android進階之旅------>Android顏色值(#AARRGGBB)透明度百分比和十六進位制對應關係以及計算方法
透明度百分比和十六進位制對應關係表格
透明度
十六進位制
100%
FF
99%
FC
98%
FA
97%
F7
96%
我的Android進階之旅------>android視訊播放只有聲音無畫面的解決辦法
今天除錯公司用VideoView實現的播放器來播放視訊的時候,只有聲音輸出而無畫面輸出。一開始以為是自己程式有問題,除錯了半天無果。懷疑是真機本身的問題,於是下了幾個第三方的
我的Android進階之旅------>android Matrix圖片隨意的放大縮小,拖動
step1:新建一個專案DragAndZoom,並準備一張照片放在res/drawable-hdpi目錄下,如下圖所示:
step2: 設定應用的UI介面,在main.xml中設定:
<?xmlversion="1.0"encoding="u
我的Android進階之旅------>Android採用AES+RSA的加密機制對http請求進行加密
本文轉載自部落格:http://blog.csdn.net/ouyang_peng/article/details/50983574
----------------------------------------------------------------------
我的Android進階之旅------>Android中可替換string的使用,getString(int resId, Object... formatArgs)
官方文件如下描述:
public finalStringgetString
(int resId,Object... formatArgs)
Return a localized formatte
[置頂] 我的Android進階之旅------>Android解決異常: startRecording() called on an uninitialized AudioRecord.
今天使用AudioRecord進行錄音操作時候,報了下面的異常。E/AndroidRuntime(22775): java.lang.IllegalStateException: startRecord
我的Android進階之旅------>Android使用百度地圖時,關於android.permission.BAIDU_LOCATION_SERVICE的宣告警告。
【重要提醒】
定位SDKv3.1版本之後,以下許可權已不需要,請取消宣告,否則將由於Android 5.0多帳戶系統加強許可權管理而導致應用安裝失敗。
<uses-permission and
我的Android進階之旅------>Android實現音樂示波器、均衡器、重低音和音場功能
package com.oyp.media;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.content.Context;
import android.gra
android-進階(3)-自定義view(2)-Android中View繪製流程以及相關方法的分析
最近正在學自定義view,這篇文章主要講view的繪製流程和一些相關的方法,淺顯易懂,寫的非常好,忍不住就轉載了。
前言: 本文是我讀《Android核心剖析》第13章----View工作原理總結而成的,在此膜拜下作者 。
android-進階(3)-自定義view(1)
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:custom="http://sch
【我的Android進階之旅】關於解析json資料中自帶轉義符號的正確操作
一、問題描述
在實現一個功能的時候,需要伺服器以json格式返回一段功能配置,比如如下所示的json配置。
1.1 我希望的json格式
{
"k": "ClientFilterTrace_android",
"isVisible": true