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