Android 自定义歌词滚动
生活随笔
收集整理的這篇文章主要介紹了
Android 自定义歌词滚动
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
本篇博客主要是通過存放本地的一篇.txt歌詞,和這個.txt文件對應的一首歌,然后點擊播放后,根據lrcview分割線來判斷歌詞滑動到那個線的時候播放,支持手勢滑動,歌詞暫停,如果有資源的話,做一個音樂播放器應該也不是問題,現在車載系統很需要這些控件,學會的話,可以從事以下其他技能。
1丶在配置清單當中加入權限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
2丶在Assets里面加入歌和歌詞:
? ? ?( ?看自己喜歡什么歌 ,在這里需要下載一首歌,和一首歌的歌詞)
在我的上一篇文章自定義雙指放大,有詳細的自定義view介紹,如果想深入了解,可以去看看。。。
MainActivity
import java.util.List; import com.example.lyricdemo.LrcView.MedCallBack; import android.R.plurals; import android.media.MediaPlayer; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.app.Activity; import android.content.res.AssetFileDescriptor; import android.view.Menu;public class MainActivity extends Activity implements MedCallBack{private LrcRows lrcRows=new LrcRows();private MediaPlayer mediaPlayer=new MediaPlayer();private boolean timeFlag=true;private LrcView lrcView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initview();}Handler handler=new Handler(){public void handleMessage(android.os.Message msg) {if (msg.what==0) {int time=mediaPlayer.getCurrentPosition();lrcView.LrcToPlayer(time);//根據播放的進度,時時跟新歌詞}};};Thread thread=new Thread(new Runnable() {@Overridepublic void run() { // TODO Auto-generated method stubwhile (timeFlag) {try {Thread.sleep(1000);} catch (Exception e) {}handler.sendEmptyMessage(0);}}});private void initview() { // TODO Auto-generated method stubList<LrcRow>list=lrcRows.BuildList(this);lrcView = (LrcView)findViewById(R.id.mylrcview);lrcView.setLrc(list);lrcView.setCall(this);try { //從assets打開AssetFileDescriptor fileDescriptor=getAssets().openFd("farawayfromhome.mp3");mediaPlayer.setDataSource(fileDescriptor.getFileDescriptor(),fileDescriptor.getStartOffset(),fileDescriptor.getLength());mediaPlayer.prepare();mediaPlayer.start();thread.start();} catch (Exception e) { // TODO: handle exception}}//歌曲播放時,根據拖動跨越的行數里面的時間快進或快退帶時間對應的播放進度@Overridepublic void call(long time) {if (mediaPlayer.isPlaying()) {mediaPlayer.seekTo((int) time);}}@Overrideprotected void onDestroy() { // TODO Auto-generated method stubsuper.onDestroy();timeFlag=false;mediaPlayer.stop();} }LrcView
import java.util.List; import android.R.bool; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Paint.Align; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View;public class LrcView extends View{private Paint paint;//畫筆private List<LrcRow>list;//歌詞數據源private int nowColor=Color.YELLOW;//正在播放的歌詞顏色private int normalColor=Color.WHITE;//其他歌詞的顏色private int lineColor=Color.CYAN;//分割線及時間顯示的顏色private float textSize=20f;//歌詞字體的大小private float timeSize=15f;//時間顯示的大小private int lineHeight=2;//分割線的高度private int marginHeight=10;//歌詞與歌詞之間的間隔private int height;//自定義視圖的高度private int width;//自定義視圖的寬;private int index=0;//正在播放的歌詞的行數private String tipstr="暫無歌詞";//默認情況下的歌詞private boolean TouchFlag=false;//手指按下的標志:當手指滑動的時候,界面不進行刷新//回調接口private MedCallBack medCallBack;private float lasty=0;//最后手指按下的坐標不public LrcView(Context context) {super(context); // TODO Auto-generated constructor stub}public LrcView(Context context, AttributeSet attrs) {super(context, attrs); //實例化畫筆, 抗鋸齒paint=new Paint(Paint.ANTI_ALIAS_FLAG);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // TODO Auto-generated method stubsuper.onMeasure(widthMeasureSpec, heightMeasureSpec); //getheight:獲得界面內的高度 //getgetMeasuredHeight:獲得視圖實際測量的高度height=getMeasuredHeight();width=getMeasuredWidth();}@Overrideprotected void onDraw(Canvas canvas) { // TODO Auto-generated method stubsuper.onDraw(canvas);paint.reset();//重置畫筆paint.setColor(nowColor);paint.setTextSize(textSize);paint.setTextAlign(Align.CENTER);if (list==null) {canvas.drawText(tipstr, width/2, height/2-textSize,paint );return;}if (list.size()==0) {canvas.drawText(tipstr, width/2,height/2-textSize, paint);return;} //繪制中間正在播放的歌詞canvas.drawText(list.get(index).row, width/2, height/2-textSize, paint); //繪制中間的分割線paint.reset();paint.setColor(lineColor);if (TouchFlag) {canvas.drawLine(0, height/2-textSize, width, height/2-textSize+lineHeight, paint);paint.setTextSize(timeSize);paint.setTextAlign(Align.LEFT);canvas.drawText(list.get(index).str_timer,0,height/2,paint);} //繪制普通的歌詞paint.reset();paint.setColor(normalColor);paint.setTextSize(textSize);paint.setTextAlign(Align.CENTER); //繪制正在播放歌詞上面的歌詞int normalIndex=0;int rowY=0;//每行歌詞的Y值normalIndex=index-1;rowY=(int)(height/2-textSize*2-marginHeight);while (normalIndex>=0&&rowY>-textSize) {canvas.drawText(list.get(normalIndex).row,width/2, rowY, paint);normalIndex--;rowY=(int) (rowY-textSize-marginHeight);} //2.繪制播放歌詞下面的歌詞normalIndex=index+1;rowY=(int) (height/2+marginHeight);while(normalIndex<list.size()&&rowY<(height+textSize)){canvas.drawText(list.get(normalIndex).row, width/2, rowY, paint);normalIndex++;rowY=(int) (rowY+marginHeight+textSize);}}@Overridepublic boolean onTouchEvent(MotionEvent event) {if (list==null) {return true;}if (list.size()==0) {return true;} //手指按下if (event.getAction()==MotionEvent.ACTION_DOWN) {TouchFlag=true;//顯示時間和分割線lasty=event.getY();//獲取你手按下的Y軸坐標//手指滑動 }else if (event.getAction()==MotionEvent.ACTION_MOVE) {float nowY=event.getY();//當前手指滑動到的Y值float disY=nowY-lasty;//計算手指滑動的Y軸的距離//判斷滑動的距離跨越幾行歌詞if (Math.abs(disY)>marginHeight) {int num=(int)(Math.abs(disY)/(marginHeight+textSize));if (num>=1) {if (disY<0) { //快進index+=num;index=Math.min(list.size()-1, index);}else if (disY>0) { //快退index-=num;index=Math.max(0,index);}}}lasty=nowY; //手指抬起}else if (event.getAction()==MotionEvent.ACTION_UP) {TouchFlag=false;//調用接口if (medCallBack!=null) {medCallBack.call(list.get(index).time);}}invalidate();//刷新布局return true;}//查找歌詞的方法,根據播放的進度跟新歌詞 ,根據傳入的參數進行當前歌曲進度的跳播public void LrcToPlayer(long time){if (list==null) {return;}if (list.size()==0) {return;}if (TouchFlag) {return;}//遍歷整個歌詞集合,尋找time的插入區間for (int i = 0; i < list.size(); i++) {LrcRow lrcRow=list.get(i);//當前的歌詞對象LrcRow lrcRow2=(i+1)>=list.size()?null:list.get(i+1);if (time>lrcRow.time&&lrcRow2!=null&&time<lrcRow2.time) {index=i;break;}if (lrcRow2==null) {index=list.size()-1;}}invalidate();}public interface MedCallBack{//接口回調吧時間回調到主啊抽屜activity中去更新歌曲播放進度public void call(long time);}//設置歌詞的方法public void setLrc(List<LrcRow>list){this.list=list;}public void setCall(MedCallBack medCallBack){this.medCallBack=medCallBack;} }LrcRows
import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; import android.content.Context; import android.content.res.AssetManager;public class LrcRows {private List<LrcRow>list=new ArrayList<LrcRow>();//存放每行歌詞的集合 //獲取list集合的方法,將每行的歌詞添加到list集合中public List<LrcRow>BuildList(Context context){//獲取assets的管理器AssetManager assetManager=context.getAssets(); //打開assets下的指定文件,獲取輸入流try {InputStream inputStream=assetManager.open("farawayfromhome.lrc"); //將字節輸入流轉化為字符流BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(inputStream));String line=null;while ((line=bufferedReader.readLine())!=null) {LrcRow lrcRow=new LrcRow();//創建每行封裝歌詞的對象 //獲取新的解析封裝好的歌詞 添加到集合中LrcRow lrcRow2=lrcRow.getRow(line);if (lrcRow2!=null) {list.add(lrcRow2);}}bufferedReader.close();} catch (Exception e) { // TODO: handle exception}return list;}}LrcRow
public class LrcRow {//每行歌詞的封裝類:每行歌詞的javaBeanpublic String row;//歌詞public String str_timer;//字符串格式的時間public long time;//每行歌詞的毫秒時間//獲取每行歌詞的 及歌詞解析的方法 public LrcRow getRow(String str){if (str==null) {return null;}if (str.equals("")) {return null;} //!=9,將 歌詞中不是歌詞的那部分給過濾掉,因為歌詞的時間字符串格式都是第九個位置為]if (str.indexOf("]")!=9) {//index of 返回指定字符串在str中第一次出現的索引return null;} //獲取每行的主題歌詞row=str.substring(str.indexOf("]")+1); //獲取字符串格式的歌詞時間 截取的時候包含開頭,不包含結尾str_timer=str.substring(1,str.indexOf("]")); //字符替換:. 替換成:---》給字符串分割的時候提供分割標志String newTime=str_timer.replace(".", ":"); //字符串的分割:自動分割成一個string類型的數組String[]arr=newTime.split(":"); //將字符串格式的時間轉換為毫秒格式的時間time=Integer.valueOf(arr[0])*60*1000+Integer.valueOf(arr[1])*1000+Integer.valueOf(arr[2]);return this;}}//以下是xml布局:
activity_main
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:background="#008AD4"tools:context=".MainActivity" > <com.example.lyricdemo.LrcViewandroid:id="@+id/mylrcview"android:layout_height="match_parent"android:layout_width="match_parent"/> </RelativeLayout>?
總結
以上是生活随笔為你收集整理的Android 自定义歌词滚动的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WORKNC基础到进阶视频教程
- 下一篇: 从头开始训练一个 NER 标注器