android播放器實(shí)現(xiàn)歌詞顯示功能
網(wǎng)上android播放器雖然挺多,感覺(jué)提供的歌詞顯示功能比較死板,要么搜索給的條件死死的,要么放置sdcard內(nèi)部的歌詞格式需要統(tǒng)一,應(yīng)該提供類似文件夾瀏覽的功能。^_^,不過(guò)在這之前先搞定歌詞的現(xiàn)實(shí)界面:
播放器的歌詞界面實(shí)現(xiàn)以下幾個(gè)功能
- 根據(jù)歌曲的播放進(jìn)度自下而上滾動(dòng);
- 提供上下拖動(dòng)調(diào)整歌曲進(jìn)度的功能;
- 突出顯示當(dāng)前進(jìn)度的歌詞段,并保證該歌詞段處于布局中心
不多說(shuō)了直接貼代碼,首先開(kāi)啟一個(gè)線程每隔一段時(shí)間往view中送入一串字符
Java代碼
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class TextAlign extends GraphicsActivity implements OnClickListener {
private SampleView mView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Animation in = AnimationUtils.loadAnimation(this, R.anim.push_up_in);
// mView.setAnimation(in);
setContentView(R.layout.main);
mView =(SampleView) findViewById(R.id.text01);
Button bt = (Button) findViewById(R.id.Button01);
bt.setOnClickListener(this);
new Thread(new UIUpdateThread()).start();
}
class UIUpdateThread implements Runnable {
long time = 40000;
long sleeptime = 100;
public void run() {
try {
while (time < 200000) {
Thread.sleep(sleeptime);
mView.updateIndex(time);//.index = mLyric.getNowSentenceIndex(time);
// Log.v("UIThread", mView.index + ":" + time);
time += sleeptime;
mHandler.post(mUpdateResults);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Handler mHandler = new Handler();
Runnable mUpdateResults = new Runnable() {
public void run() {
mView.invalidate(); // 更新視圖
}
};
@Override
public void onClick(View v) {
mView.mTouchHistoryY -=30;
mHandler.post(mUpdateResults);
}
}
這里將時(shí)間送到SampleView中,該類對(duì)此時(shí)間進(jìn)行加工得到一系列l(wèi)ist(該list是動(dòng)態(tài)生成的),從而根據(jù)時(shí)間的推移遞增的得到一系列的字串。這個(gè)過(guò)程模擬了歌詞的顯示過(guò)程
接下來(lái)的SampleView繼承了TextView并重載了onDraw方法.注意,這里只給了個(gè)sample,里面歌詞怎么生成的見(jiàn)YOYOPlayer。這里就不給代碼了
Java代碼
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.util.Log;
import android.view.MotionEvent;
import android.widget.TextView;
import android.widget.Toast;
import com.android.lyric.Lyric;
import com.android.lyric.PlayListItem;
import com.android.lyric.Sentence;
public class SampleView extends TextView {
private Paint mPaint;
private float mX;
private static Lyric mLyric;
private Path mPath;
private Paint mPathPaint;
public String test = "test";
public int index = 0;
private List<Sentence> list;
private float mTouchStartY;
private float mTouchCurrY;
public float mTouchHistoryY;
private int mY;
private long currentTime;
private long currentDunringTime;
private long sentenctTime;
private float middleY;
private String middleContent="Empty";
private static final int DY = 30;
private static void makePath(Path p) {
p.moveTo(10, 0);
p.cubicTo(100, -50, 200, 50, 300, 0);
}
public SampleView(Context context) {
super(context);
init();
}
public SampleView(Context context,AttributeSet attr) {
super(context,attr);
init();
}
public SampleView(Context context,AttributeSet attr,int i) {
super(context,attr,i);
init();
}
private void init() {
setFocusable(true);
PlayListItem pli = new PlayListItem("", "", 1000L, true);
mLyric = new Lyric(new File("/sdcard/M0005044007.lrc"), pli);
list = mLyric.list;
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setTextSize(20);
mPaint.setTypeface(Typeface.SERIF);
mPath = new Path();
makePath(mPath);
mPathPaint = new Paint();
mPathPaint.setAntiAlias(true);
mPathPaint.setColor(0x800000FF);
mPathPaint.setStyle(Paint.Style.STROKE);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.WHITE);
Paint p = mPaint;
float x = mX;
float plus =currentDunringTime==0?index*30: index*30 +(((float)currentTime - (float)sentenctTime)/(float)currentDunringTime)*(float)30;
float y = mY- plus+mTouchCurrY - mTouchStartY+mTouchHistoryY;
canvas.translate(0,y);
for (int i = 0; i < index; i++) {
String text = list.get(i).getContent();
if((y+i*30)<=middleY&&(y+i*30+30)>=middleY)
middleContent = text;
p.setTextAlign(Paint.Align.CENTER);
canvas.drawText(text, x, 0, p);
// mY- mY/lines*(index - i)
canvas.translate(0, DY);
}
}
@Override
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;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mTouchHistoryY += mTouchCurrY - mTouchStartY;
mTouchStartY =mTouchCurrY= y;
invalidate();
break;
case MotionEvent.ACTION_MOVE:
mTouchCurrY = y;
invalidate();
break;
case MotionEvent.ACTION_UP:
Log.v("Lyric content", middleContent.length()+"");
CharSequence chars = new CharSequence(){
@Override
public char charAt(int index) {
// TODO Auto-generated method stub
return middleContent.charAt(index);
}
@Override
public int length() {
// TODO Auto-generated method stub
return middleContent.length();
}
@Override
public CharSequence subSequence(int start, int end) {
// TODO Auto-generated method stub
return middleContent.subSequence(start, end);
}
@Override
public String toString(){
return middleContent;
}
};
Toast toast = Toast.makeText(SampleView.this.getContext(),chars, 1000);
toast.show();
invalidate();
break;
}
return true;
}
public void updateIndex(long time) {
this.currentTime = time;
index = mLyric.getNowSentenceIndex(time);
Sentence sen = list.get(index);
currentDunringTime = sen.getDuring();
sentenctTime = sen.getFromTime();
}
}
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
kotlin中object關(guān)鍵字的三種使用場(chǎng)景
這篇文章主要給大家介紹了關(guān)于kotlin中object關(guān)鍵字的三種使用場(chǎng)景,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用kotlin具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06
Android實(shí)現(xiàn)定時(shí)任務(wù)功能
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)定時(shí)任務(wù)功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01
Android 動(dòng)態(tài)改變SeekBar進(jìn)度條顏色與滑塊顏色的實(shí)例代碼
在上次android開(kāi)發(fā)的項(xiàng)目中遇到個(gè)這樣的需求,要?jiǎng)討B(tài)改變seekbar進(jìn)度條顏色與滑塊顏色的需求,實(shí)現(xiàn)代碼也算比較簡(jiǎn)單,對(duì)實(shí)現(xiàn)過(guò)程感興趣的朋友可以通過(guò)本文學(xué)習(xí)下2016-11-11
Flutter?Widget?之package?mason實(shí)現(xiàn)詳解
這篇文章主要為大家介紹了Flutter?Widget?之package:?mason實(shí)現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11
Android fragment 轉(zhuǎn)場(chǎng)動(dòng)畫(huà)創(chuàng)建步驟
在 Android 中,可以使用 setCustomAnimations() 方法來(lái)繪制自定義的 Fragment 轉(zhuǎn)場(chǎng)動(dòng)畫(huà),本文分步驟給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-03-03
Android開(kāi)發(fā)圖片水平旋轉(zhuǎn)180度方法
今天小編就為大家分享一篇Android開(kāi)發(fā)圖片水平旋轉(zhuǎn)180度方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-08-08

