## 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;
}
}
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 lrcLists = new ArrayList();
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 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 getLrcLists() {
return lrcLists;
}
public void setLrcLists(ArrayList lrcLists) {
this.lrcLists = lrcLists;
}
}
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