android實現(xiàn)歌詞自動滾動效果
最近在做Android 的MP3播放的項目,要實現(xiàn)歌詞的自動滾動,以及同步顯示。
lyric的歌詞解析主要用yoyoplayer里面的,顯示部分參考了這里 ,這里只是模擬MP3歌詞的滾動。
先上一下效果圖:

滾動實現(xiàn)的代碼其實也簡單。顯示畫出當前時間點的歌詞,然后再分別畫出改歌詞后面和前面的歌詞,前面的部分往上推移,后面的部分往下推移,這樣就保持了當前時間歌詞在中間。
代碼如下 LyricView,相關(guān)信息在注釋了標明了。
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; // 當前行歌詞持續(xù)的時間,用該時間來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);
// 返回歌詞持續(xù)的時間,在這段時間內(nèi)sleep
return currentDunringTime = sen.getDuring();
}
}
剩下的就是使用他了。就是取出歌詞的index,和該行歌詞持續(xù)的時間進行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部分代碼。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Flutter有狀態(tài)組件StatefulWidget生命周期詳解
這篇文章主要為大家介紹了Flutter有狀態(tài)組件StatefulWidget生命周期詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-01-01
Android中的應(yīng)用認領(lǐng)總結(jié)
這篇文章主要介紹了Android中的應(yīng)用認領(lǐng)總結(jié),本文講解了如何認領(lǐng)、對未簽名包簽名、需要替換的簽名值、驗證簽名等內(nèi)容,需要的朋友可以參考下2015-01-01
關(guān)于Android Fragment對回退棧的詳細理解
這篇文章主要介紹了Android Fragment的回退棧示例詳細介紹的相關(guān)資料,在Android中Fragment回退棧是由Activity管理的,每個Activity都有自己的回退棧,其中保存了已經(jīng)停止(處于后臺)的Fragment實例,需要的朋友可以參考下2016-12-12
Android 深入探究自定義view之流式布局FlowLayout的使用
FlowLayout(int align, int hgap, int vgap)創(chuàng)建一個新的流布局管理器,它具有指定的對齊方式以及指定的水平和垂直間隙,意思就是說從左上角開始添加原件,依次往后排,第一行擠滿了就換一行接著排2021-11-11
Android自定義View實現(xiàn)水波紋引導(dǎo)動畫
這篇文章主要為大家詳細介紹了Android自定義View實現(xiàn)水波紋動畫引導(dǎo),具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-01-01

