最近在做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部分代码。