1. 程式人生 > >Android練習專案 Mp3播放器實現 歌詞同步播放(四)

Android練習專案 Mp3播放器實現 歌詞同步播放(四)

其實到後面就需要我們如何顯示歌詞,對於歌詞的同步顯示還是比較好實現的,主要通過判斷當前播放的時間和每個結點的歌詞的時間的大小,來同步對應到結點的資料,現在就是如何來實現這個問題。

其實,這個時候就需要自定義控制元件來實現。
第一步需要自定義View的屬性。
第二步需要實現在View的構造方法中獲得我們自定義的屬性。
主要通過初始化函式,init()
第三步,重寫ondraw函式。

LrcView.java

package com.flashmusic.View;


import android.content.Context;
import android.graphics.Canvas;
import
android.graphics.Color; import android.graphics.Paint; import android.graphics.Typeface; import android.util.AttributeSet; import android.widget.TextView; import com.flashmusic.tool.LrcInfo; import com.flashmusic.tool.LrcList; import java.util.Map; /** * Created by zhouchenglin on 2016/4/20. */ public
class LrcView extends TextView { private float width; //歌詞檢視寬度 private float height; //歌詞檢視高度 private Paint currentPaint; //當前畫筆物件 private Paint notCurrentPaint; //非當前畫筆物件 private float textHeight = 65; //文字高度 private float textMaxSize = 50
; private float textSize = 40; //文字大小 private int index = 0; //list集合下標 private LrcInfo infos; //歌詞資訊 public void setmLrcList(LrcInfo infos) { this.infos = infos; } public LrcView(Context context) { super(context); init(); } public LrcView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } public LrcView(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { setFocusable(true); //設定可對焦 //顯示歌詞部分 currentPaint = new Paint(); currentPaint.setAntiAlias(true); //設定抗鋸齒,讓文字美觀飽滿 currentPaint.setTextAlign(Paint.Align.CENTER);//設定文字對齊方式 //非高亮部分 notCurrentPaint = new Paint(); notCurrentPaint.setAntiAlias(true); notCurrentPaint.setTextAlign(Paint.Align.CENTER); } /** * 繪畫歌詞 */ @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (canvas == null) { return; } currentPaint.setColor(Color.argb(210, 251, 248, 29)); notCurrentPaint.setColor(Color.argb(140, 255, 255, 255)); currentPaint.setTextSize(textMaxSize); currentPaint.setTypeface(Typeface.SERIF); notCurrentPaint.setTextSize(textSize); notCurrentPaint.setTypeface(Typeface.DEFAULT); try { setText(""); canvas.drawText(infos.getLrcLists().get(index).getContent(), width / 2, height / 2, currentPaint); float tempY = height / 2; //畫出本句之前的句子 for (int i = index - 1; i >= 0; i--) { //向上推移 tempY = tempY - textHeight; canvas.drawText(infos.getLrcLists().get(i).getContent(), width / 2, tempY, notCurrentPaint); } tempY = height / 2; //畫出本句之後的句子 for (int i = index + 1; i < infos.getLrcLists().size(); i++) { //往下推移 tempY = tempY + textHeight; canvas.drawText(infos.getLrcLists().get(i).getContent(), width / 2, tempY, notCurrentPaint); } } catch (Exception e) { setText("...木有歌詞檔案,趕緊去下載..."); } } /** * 當view大小改變的時候呼叫的方法 */ protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); this.width = w; this.height = h; } public void setIndex(int index) { this.index = index; } }

這個類是別人實現了,我仔細研讀了下,覺得寫的不錯,通過下標的判斷來實現文字的顯示,這個比較不錯,值得學習。

接下來就需要在Musicservice.java裡面初始化函式的獲得。

 public void initLrc() {

        //建立歌詞物件
       LrcParse lrcParser = new LrcParse(path);
        //讀歌詞,並將資料傳給歌詞資訊類
        lrcInfo = lrcParser.readLrc();
        //獲得歌詞中的結點
        lrcLists = lrcInfo.getLrcLists();
        //在musicActivity裡面設定靜態來共享資料
        MusicActivity.lrcView.setmLrcList(lrcInfo);
        //切換帶動畫顯示歌詞
        MusicActivity.lrcView.setAnimation(AnimationUtils.loadAnimation(MusicService.this, R.anim.alpha_z));
        mHandler.post(mRunnable);

    }

    Runnable mRunnable = new Runnable() {

        @Override
        public void run() {
            MusicActivity.lrcView.setIndex(lrcIndex());
            MusicActivity.lrcView.invalidate();
            mHandler.postDelayed(mRunnable, 100);
        }
    };

Handle主要通過Runnable來實現MusicActivity裡面歌詞的同步,但同步還是需要判斷自定義控制元件裡面的index屬性。

lrcIndex函式的判斷,通過比較時間來獲得具體的index.

  public int lrcIndex() {
        if (mediaPlayer.isPlaying()) {
            currentTime = mediaPlayer.getCurrentPosition();
            duration = mediaPlayer.getDuration();
        }
        if (currentTime < duration) {
            for (int i = 0; i < lrcLists.size(); i++) {
                if (i < lrcLists.size() - 1) {
                    if (currentTime < lrcLists.get(i).getCurrentTime() && i == 0) {
                        index = i;
                    }
                    if ((currentTime > lrcLists.get(i).getCurrentTime())&& currentTime < lrcLists.get(i+1).getCurrentTime()) {
                        index = i;
                    }
                }
                if ((i == lrcLists.size() - 1)&& currentTime > lrcLists.get(i).getCurrentTime()) {
                    index = i;
                }
            }
        }
        return index;
    }

接下來就是如何呼叫初始化函式,因為我們每次播放的時候,才顯示歌詞的同步,所以我將他放在初始化的函式裡面,問題就可以搞定了。
看看play函式,只需要新增一行程式碼就完成了。

 private void play(int currentTime) {
        try {

            mediaPlayer.reset();// 把各項引數恢復到初始狀態
            mediaPlayer.setDataSource(path);
            mediaPlayer.prepare(); // 進行緩衝
            mediaPlayer.setOnPreparedListener(new PreparedListener(currentTime));// 註冊一個監聽器

            initLrc();
            //更新播放狀態
            Intent intent = new Intent(PLAY_STATUE);
            // 傳送播放完畢的訊號,更新播放狀態
            intent.putExtra("playstatue", true);
            sendBroadcast(intent);
            mHandler.sendEmptyMessage(1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

看看實現的效果:
星弟的歌,本人比較喜歡

jj
沒有歌詞

對於文章中出現的有些類名,可以看之前寫的系列文章。
現在一款本地音樂播放器的功能基本實現了,這裡面用到了很多的知識,對android這個系統的瞭解又更加加深了理解,感謝前輩們的部落格,讓我受益匪淺,謝謝技術的分享,現在我也是為了更多的人,來分享自己的部落格。讓我們在技術的海洋中不斷進步。