Android練習專案 Mp3播放器實現 歌詞同步播放(四)
阿新 • • 發佈:2018-12-31
其實到後面就需要我們如何顯示歌詞,對於歌詞的同步顯示還是比較好實現的,主要通過判斷當前播放的時間和每個結點的歌詞的時間的大小,來同步對應到結點的資料,現在就是如何來實現這個問題。
其實,這個時候就需要自定義控制元件來實現。
第一步需要自定義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();
}
}
看看實現的效果:
對於文章中出現的有些類名,可以看之前寫的系列文章。
現在一款本地音樂播放器的功能基本實現了,這裡面用到了很多的知識,對android這個系統的瞭解又更加加深了理解,感謝前輩們的部落格,讓我受益匪淺,謝謝技術的分享,現在我也是為了更多的人,來分享自己的部落格。讓我們在技術的海洋中不斷進步。