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

滾動實(shí)現(xiàn)的代碼其實(shí)也簡單。顯示畫出當(dāng)前時間點(diǎn)的歌詞,然后再分別畫出改歌詞后面和前面的歌詞,前面的部分往上推移,后面的部分往下推移,這樣就保持了當(dāng)前時間歌詞在中間。
代碼如下 LyricView,相關(guān)信息在注釋了標(biāo)明了。
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; // 當(dāng)前行歌詞持續(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);
// 高亮部分 當(dāng)前歌詞
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);
// 先畫當(dāng)前行,之后再畫他的前面和后面,這樣就保持當(dāng)前行在中間的位置
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
* 當(dāng)前歌詞的時間軸
*
* @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ù)的時間進(jìn)行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)文章
Android之帶group指示器的ExpandableListView(自寫)
Android缺省的ExpandableListView的group header無法固定在界面上,在網(wǎng)上搜索了好多都不盡人意,于是乎在別人的基礎(chǔ)上改進(jìn)了一點(diǎn)點(diǎn),原理都差不多2013-06-06
Android實(shí)現(xiàn)簡單計(jì)時器功能
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)簡單計(jì)時器功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-10-10
Android中監(jiān)聽系統(tǒng)網(wǎng)絡(luò)連接打開或者關(guān)閉的實(shí)現(xiàn)代碼
本篇文章對Android中監(jiān)聽系統(tǒng)網(wǎng)絡(luò)連接打開或者關(guān)閉的實(shí)現(xiàn)用實(shí)例進(jìn)行了介紹。需要的朋友參考下2013-05-05
Android ListView 實(shí)例講解清晰易懂
這篇文章主要通過實(shí)例介紹了Android ListView,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-09-09
安卓(Android)動態(tài)創(chuàng)建多個按鈕并添加監(jiān)聽事件
本文主要介紹Android動態(tài)創(chuàng)建多個按鈕并給每個按鍵添加監(jiān)聽事件,在做Android項(xiàng)目會經(jīng)常遇到的,希望對需要用到的同學(xué)有所幫助2016-07-07
Android沉浸式狀態(tài)欄微技巧(帶你真正理解沉浸式模式)
因?yàn)锳ndroid官方從來沒有給出過沉浸式狀態(tài)欄這樣的命名,只有沉浸式模式(Immersive Mode)這種說法.下面通過本文給大家介紹Android沉浸式狀態(tài)欄微技巧,需要的朋友參考下2016-12-12
替換so文件來動態(tài)替換Flutter代碼實(shí)現(xiàn)詳解
這篇文章主要為大家介紹了替換so文件來動態(tài)替換Flutter代碼實(shí)現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
Android調(diào)用默認(rèn)瀏覽器打開指定Url的方法實(shí)例
業(yè)務(wù)員有需求要將一個wap站在手機(jī)上以App的形式打開,還不要嵌套WebView,只能以瀏覽器打開.查了點(diǎn)資料,就有了下面這代碼2013-09-09

