實現歌詞滾動
阿新 • • 發佈:2019-01-03
## LrcView 自定義控制元件 ## package com.example.music.lrc; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Typeface; import android.util.AttributeSet; import android.widget.TextView; public class LrcView extends TextView { private float width; // 歌詞檢視寬度 private float height; // 歌詞檢視高度 private Paint currentPaint; // 當前畫筆物件 private Paint notCurrentPaint; // 非當前畫筆物件 private float textHeight = 50; // 文字高度 private float textMaxSize = 24; //高亮文字大小 private float textSize = 20; // 文字大小 private int index = 0; // list集合下標 private LrcInfo infos; // 歌詞資訊 public void setmLrcList(LrcInfo infos) { this.infos = infos; } public LrcView(Context context) { super(context); init(); } public LrcView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } public LrcView(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { setFocusable(true); // 設定可對焦 // 顯示歌詞部分 currentPaint = new Paint(); currentPaint.setAntiAlias(true); // 設定抗鋸齒,讓文字美觀飽滿 currentPaint.setTextAlign(Paint.Align.CENTER);// 設定文字對齊方式 // 非高亮部分 notCurrentPaint = new Paint(); notCurrentPaint.setAntiAlias(true); notCurrentPaint.setTextAlign(Paint.Align.CENTER); } /** * 繪畫歌詞 */ @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (canvas == null) { return; } currentPaint.setColor(Color.argb(210, 251, 248, 29)); notCurrentPaint.setColor(Color.argb(140, 255, 255, 255)); currentPaint.setTextSize(textMaxSize); currentPaint.setTypeface(Typeface.SERIF); notCurrentPaint.setTextSize(textSize); notCurrentPaint.setTypeface(Typeface.DEFAULT); try { setText(""); canvas.drawText(infos.getLrcLists().get(index).getContent(), width / 2, height / 2, currentPaint); float tempY = height / 2; // 畫出本句之前的句子 for (int i = index - 1; i >= 0; i--) { // 向上推移 tempY = tempY - textHeight; canvas.drawText(infos.getLrcLists().get(i).getContent(), width / 2, tempY, notCurrentPaint); } tempY = height / 2; // 畫出本句之後的句子 for (int i = index + 1; i < infos.getLrcLists().size(); i++) { // 往下推移 tempY = tempY + textHeight; canvas.drawText(infos.getLrcLists().get(i).getContent(), width / 2, tempY, notCurrentPaint); } } catch (Exception e) { setText("...缺少歌詞檔案..."); } } /** * 當view大小改變的時候呼叫的方法 */ protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); this.width = w; this.height = h; } public void setIndex(int index) { this.index = index; } }
LrcParse 類
package com.example.music.lrc;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class LrcParse {
private LrcInfo lrcInfo = new LrcInfo();
public static String charSet = "utf-8"; //編碼格式
//歌詞存放地地方
private String Path;
//時間
private long currentTime;
//對應時間的內容
private String currentContent;
//儲存時間點和內容
ArrayList<LrcList> lrcLists = new ArrayList<LrcList>();
private InputStream inputStream;
public LrcParse(String path) {
this.Path = path.replace(".mp3", ".lrc");
}
public LrcInfo readLrc() {
//定義一個StringBuilder物件,用來存放歌詞內容
StringBuilder stringBuilder = new StringBuilder();
try {
inputStream = new FileInputStream(this.Path);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, charSet));
String str = null;
//逐行解析
while ((str = reader.readLine()) != null) {
if (!str.equals("")) {
decodeLine(str);
}
}
//全部解析完後,設定lrcLists
lrcInfo.setLrcLists(lrcLists);
return lrcInfo;
} catch (FileNotFoundException e) {
e.printStackTrace();
LrcList lrcList = new LrcList();
//設定時間點和內容的對映
lrcList.setContent("歌詞檔案沒發現!");
lrcLists.add(lrcList);
lrcInfo.setLrcLists(lrcLists);
return lrcInfo;
} catch (IOException e) {
e.printStackTrace();
LrcList lrcList = new LrcList();
//設定時間點和內容的對映
lrcList.setContent("沒有讀取到歌詞!");
lrcLists.add(lrcList);
lrcInfo.setLrcLists(lrcLists);
return lrcInfo;
}
}
/**
* 單行解析
*/
private LrcInfo decodeLine(String str) {
if (str.startsWith("[ti:")) {
// 歌曲名
lrcInfo.setTitle(str.substring(4, str.lastIndexOf("]")));
// lrcTable.put("ti", str.substring(4, str.lastIndexOf("]")));
} else if (str.startsWith("[ar:")) {// 藝術家
lrcInfo.setArtist(str.substring(4, str.lastIndexOf("]")));
} else if (str.startsWith("[al:")) {// 專輯
lrcInfo.setAlbum(str.substring(4, str.lastIndexOf("]")));
} else if (str.startsWith("[by:")) {// 作詞
lrcInfo.setBySomeBody(str.substring(4, str.lastIndexOf("]")));
} else if (str.startsWith("[la:")) {// 語言
lrcInfo.setLanguage(str.substring(4, str.lastIndexOf("]")));
} else {
//設定正則表示式,可能出現一些特殊的情況
String timeflag = "\\[(\\d{1,2}:\\d{1,2}\\.\\d{1,2})\\]|\\[(\\d{1,2}:\\d{1,2})\\]";
Pattern pattern = Pattern.compile(timeflag);
Matcher matcher = pattern.matcher(str);
//如果存在匹配項則執行如下操作
while (matcher.find()) {
//得到匹配的內容
String msg = matcher.group();
//得到這個匹配項開始的索引
int start = matcher.start();
//得到這個匹配項結束的索引
int end = matcher.end();
//得到這個匹配項中的陣列
int groupCount = matcher.groupCount();
for (int index = 0; index < groupCount; index++) {
String timeStr = matcher.group(index);
if (index == 0) {
//將第二組中的內容設定為當前的一個時間點
currentTime = str2Long(timeStr.substring(1, timeStr.length() - 1));
}
}
//得到時間點後的內容
String[] content = pattern.split(str);
//將內容設定為當前內容,需要判斷只出現時間的情況,沒有內容的情況
if (content.length == 0) {
currentContent = "";
} else {
currentContent = content[content.length - 1];
}
LrcList lrcList = new LrcList();
//設定時間點和內容的對映
lrcList.setCurrentTime(currentTime);
lrcList.setContent(currentContent);
lrcLists.add(lrcList);
}
}
return this.lrcInfo;
}
private long str2Long(String timeStr) {
//將時間格式為xx:xx.xx,返回的long要求以毫秒為單位
String[] s = timeStr.split("\\:");
int min = Integer.parseInt(s[0]);
int sec = 0;
int mill = 0;
if (s[1].contains(".")) {
String[] ss = s[1].split("\\.");
sec = Integer.parseInt(ss[0]);
mill = Integer.parseInt(ss[1]);
} else {
sec = Integer.parseInt(s[1]);
}
//時間的組成
return min * 60 * 1000 + sec * 1000 + mill * 10;
}
}
package com.example.music.lrc;
public class LrcList {
//儲存當前時間
private long currentTime;
//儲存內容
private String content;
public long getCurrentTime() {
return currentTime;
}
public void setContent(String content) {
this.content = content;
}
public void setCurrentTime(long currentTime) {
this.currentTime = currentTime;
}
public String getContent() {
return content;
}
}
package com.example.music.lrc;
import java.util.ArrayList;
public class LrcInfo {
private String title;//標題
private String artist;//歌手
private String album;//專輯名字
private String bySomeBody;//歌詞製作者
private String offset;
private String language; //語言
private String errorinfo; //錯誤資訊
//儲存歌詞資訊和時間點
ArrayList<LrcList> lrcLists;
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
public void setErrorinfo(String errorinfo) {
this.errorinfo = errorinfo;
}
public String getErrorinfo() {
return errorinfo;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getArtist() {
return artist;
}
public void setArtist(String artist) {
this.artist = artist;
}
public String getAlbum() {
return album;
}
public void setAlbum(String album) {
this.album = album;
}
public String getBySomeBody() {
return bySomeBody;
}
public void setBySomeBody(String bySomeBody) {
this.bySomeBody = bySomeBody;
}
public String getOffset() {
return offset;
}
public void setOffset(String offset) {
this.offset = offset;
}
public ArrayList<LrcList> getLrcLists() {
return lrcLists;
}
public void setLrcLists(ArrayList<LrcList> lrcLists) {
this.lrcLists = lrcLists;
}
}
然後在到MusicService服務類裡面呼叫
Handler handler = new Handler() {
};
public void initLrc(String path) {
LrcInfo mlrcInfo = new LrcInfo();
//建立歌詞物件
LrcParse lrcParser = new LrcParse(path);
//讀歌詞,並將資料傳給歌詞資訊類
mlrcInfo = lrcParser.readLrc();
//獲得歌詞中的結點
lrcLists = mlrcInfo.getLrcLists();
//在MainActivity裡面設定靜態來共享資料
MainActivity.lrcView.setmLrcList(mlrcInfo);
//切換帶動畫顯示歌詞
MainActivity.lrcView.setAnimation(AnimationUtils.loadAnimation(MusicService.this, R.anim.alpha_z));
handler.post(mRunnable);
}
Runnable mRunnable = new Runnable() {
@Override
public void run() {
MainActivity.lrcView.setIndex(lrcIndex());
MainActivity.lrcView.invalidate();
handler.postDelayed(mRunnable, 100);
}
};
public int lrcIndex() {
if (mediaPlayer.isPlaying()) {
curplaytime2 = mediaPlayer.getCurrentPosition();
duration2 = mediaPlayer.getDuration();
}
if (curplaytime2 < duration2) {
for (int i = 0; i < lrcLists.size(); i++) {
if (i < lrcLists.size() - 1) {
if (curplaytime2 < lrcLists.get(i).getCurrentTime() && i == 0) {
index = i;
}
if ((curplaytime2 > lrcLists.get(i).getCurrentTime())&& curplaytime2 < lrcLists.get(i+1).getCurrentTime()) {
index = i;
}
}
if ((i == lrcLists.size() - 1)&& curplaytime2 > lrcLists.get(i).getCurrentTime()) {
index = i;
}
}
}
return index;
}
MainActivity就是主活動介面,在介面初始化自定義控制元件,當然也要在佈局檔案裡面加上佈局。R.anim.alpha_z 這個我也不知道是效果,所以不寫了
歌詞檔案可以自己製作哦,在百度裡面搜尋lrc格式的歌詞,然後自己新建一個資料夾,改一下字尾.lrc,當然檔名要跟歌曲名一樣
摘抄自http://blog.csdn.net/wwj_748/article/details/9006567