最近在做Android 的MP3播放的项目,要实现歌词的自动滚动,以及同步显示。
lyric的歌词解析主要用yoyoplayer里面的,
显示部分参考了http://ishelf.iteye.com/blog/740402 ,这里只是模拟MP3歌词的滚动。
先上一下效果图:
滚动实现的代码其实也简单。显示画出当前时间点的歌词,然后再分别画出改歌词后面和前面的歌词,前面的部分往上推移,后面的部分往下推移,这样就保持了当前时间歌词在中间。
代码如下 LyricView,相关信息在注释了标明了。
package ru.org.piaozhiye.lyric;
import java.io.File;
import java.util.List;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.widget.TextView;
/**
* @author root
*
*/
public class LyricView extends TextView {
private Paint mPaint;
private float mX;
private static Lyric mLyric;
private Paint mPathPaint;
public String test = "test";
public int index = 0;
private List<Sentence> list;
public float mTouchHistoryY;
private int mY;
private long currentDunringTime; // 当前行歌词持续的时间,用该时间来sleep
private float middleY;// y轴中间
private static final int DY = 50; // 每一行的间隔
public LyricView(Context context) {
super(context);
init();
}
public LyricView(Context context, AttributeSet attr) {
super(context, attr);
init();
}
public LyricView(Context context, AttributeSet attr, int i) {
super(context, attr, i);
init();
}
private void init() {
setFocusable(true);
PlayListItem pli = new PlayListItem("Because Of You",
"/sdcard/MP3/Because Of You.mp3", 0L, true);
mLyric = new Lyric(new File("/sdcard/MP3/Because Of You.lrc"), pli);
list = mLyric.list;
// 非高亮部分
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setTextSize(22);
mPaint.setColor(Color.WHITE);
mPaint.setTypeface(Typeface.SERIF);
// 高亮部分 当前歌词
mPathPaint = new Paint();
mPathPaint.setAntiAlias(true);
mPathPaint.setColor(Color.RED);
mPathPaint.setTextSize(22);
mPathPaint.setTypeface(Typeface.SANS_SERIF);
}
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(0xEFeffff);
Paint p = mPaint;
Paint p2 = mPathPaint;
p.setTextAlign(Paint.Align.CENTER);
if (index == -1)
return;
p2.setTextAlign(Paint.Align.CENTER);
// 先画当前行,之后再画他的前面和后面,这样就保持当前行在中间的位置
canvas.drawText(list.get(index).getContent(), mX, middleY, p2);
float tempY = middleY;
// 画出本句之前的句子
for (int i = index - 1; i >= 0; i--) {
// Sentence sen = list.get(i);
// 向上推移
tempY = tempY - DY;
if (tempY < 0) {
break;
}
canvas.drawText(list.get(i).getContent(), mX, tempY, p);
// canvas.translate(0, DY);
}
tempY = middleY;
// 画出本句之后的句子
for (int i = index + 1; i < list.size(); i++) {
// 往下推移
tempY = tempY + DY;
if (tempY > mY) {
break;
}
canvas.drawText(list.get(i).getContent(), mX, tempY, p);
// canvas.translate(0, DY);
}
}
protected void onSizeChanged(int w, int h, int ow, int oh) {
super.onSizeChanged(w, h, ow, oh);
mX = w * 0.5f; // remember the center of the screen
mY = h;
middleY = h * 0.5f;
}
//
/**
* @param time
* 当前歌词的时间轴
*
* @return currentDunringTime 歌词只需的时间
*/
public long updateIndex(long time) {
// 歌词序号
index = mLyric.getNowSentenceIndex(time);
if (index == -1)
return -1;
Sentence sen = list.get(index);
// 返回歌词持续的时间,在这段时间内sleep
return currentDunringTime = sen.getDuring();
}
}
剩下的就是使用他了。就是取出歌词的index,和该行歌词持续的时间进行sleep。
package ru.org.piaozhiye;
import java.io.IOException;
import ru.org.piaozhiye.lyric.LyricView;
import android.app.Activity;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Handler;
public class LyricDemo extends Activity {
private MediaPlayer mp;
private LyricView lyricView;
private String path = "/sdcard/MP3/Because Of You.mp3";
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
lyricView = (LyricView) findViewById(R.id.audio_lrc);
mp = new MediaPlayer();
mp.reset();
try {
mp.setDataSource(path);
mp.prepare();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mp.start();
new Thread(new UIUpdateThread()).start();
}
class UIUpdateThread implements Runnable {
long time = 100; // 开始 的时间,不能为零,否则前面几句歌词没有显示出来
public void run() {
while (mp.isPlaying()) {
long sleeptime = lyricView.updateIndex(time);
time += sleeptime;
mHandler.post(mUpdateResults);
if (sleeptime == -1)
return;
try {
Thread.sleep(sleeptime);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Handler mHandler = new Handler();
Runnable mUpdateResults = new Runnable() {
public void run() {
lyricView.invalidate(); // 更新视图
}
};
}
整个project的源码。包括yoyoplayer的解析lyric部分代码。
http://download.csdn.NET/source/3186718