Android应用开发--MP3音乐播放器滚动歌词实现

来源:互联网 发布:java web权限控制 编辑:程序博客网 时间:2024/04/27 23:45

文章出自:http://blog.csdn.net/wwj_748/article/details/9006567

Android应用开发--MP3音乐播放器滚动歌词实现

2013年6月2日  简、美音乐播放器开发记录

-----前话

有网友给我博客评论说,让我借鉴好的Android代码,代码贴出来的时候最好整体先看一下。其实小巫也有参考过别人的代码,主要是具体看某一个功能是怎么实现的,但是因为开发的思路不一样,只能说自己去写一些符合自己思路的代码。编写代码过程中,或多或少有纰漏之处,但基本上能实现功能就行了。小巫的功底还不够,不具备很强的重构代码的能力,一直都是以最直观的想法来编程,并没有太过关注性能的优化啥的,因为我也没发现自己开发的这款音乐播放器用起来不爽。不过,小巫会一直学习的,努力提升自己的编程水平,争取生产出优美的代码供朋友们参考。

-----主题

     这篇博客的主题是:“滚动歌词的实现”

     要的效果如下:

           

----实现过程

1. 建立歌词内容实体类

2. 自定义View

3. 加入布局文件

4. 编写歌词处理类

5. 在Service里面实现同步更新歌词


----代码实现

--LrcContent.java

[java] view plaincopy
  1. package com.wwj.sb.domain;  
  2. /** 
  3.  * 2013/6/1 
  4.  * @author wwj 
  5.  * 歌词实体类 
  6.  */  
  7. public class LrcContent {  
  8.     private String lrcStr;  //歌词内容  
  9.     private int lrcTime;    //歌词当前时间  
  10.     public String getLrcStr() {  
  11.         return lrcStr;  
  12.     }  
  13.     public void setLrcStr(String lrcStr) {  
  14.         this.lrcStr = lrcStr;  
  15.     }  
  16.     public int getLrcTime() {  
  17.         return lrcTime;  
  18.     }  
  19.     public void setLrcTime(int lrcTime) {  
  20.         this.lrcTime = lrcTime;  
  21.     }  
  22. }  


--LrcView.java

[java] view plaincopy
  1. package com.wwj.sb.custom;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. import android.content.Context;  
  7. import android.graphics.Canvas;  
  8. import android.graphics.Color;  
  9. import android.graphics.Paint;  
  10. import android.graphics.Typeface;  
  11. import android.util.AttributeSet;  
  12.   
  13. import com.wwj.sb.domain.LrcContent;  
  14.   
  15. /** 
  16.  * 自定义绘画歌词,产生滚动效果 
  17.  * @author wwj 
  18.  * 
  19.  */  
  20. public class LrcView extends android.widget.TextView {  
  21.     private float width;        //歌词视图宽度  
  22.     private float height;       //歌词视图高度  
  23.     private Paint currentPaint; //当前画笔对象  
  24.     private Paint notCurrentPaint;  //非当前画笔对象  
  25.     private float textHeight = 25;  //文本高度  
  26.     private float textSize = 18;        //文本大小  
  27.     private int index = 0;      //list集合下标  
  28.       
  29.       
  30.     private List<LrcContent> mLrcList = new ArrayList<LrcContent>();  
  31.       
  32.     public void setmLrcList(List<LrcContent> mLrcList) {  
  33.         this.mLrcList = mLrcList;  
  34.     }  
  35.   
  36.     public LrcView(Context context) {  
  37.         super(context);  
  38.         init();  
  39.     }  
  40.     public LrcView(Context context, AttributeSet attrs, int defStyle) {  
  41.         super(context, attrs, defStyle);  
  42.         init();  
  43.     }  
  44.   
  45.     public LrcView(Context context, AttributeSet attrs) {  
  46.         super(context, attrs);  
  47.         init();  
  48.     }  
  49.   
  50.     private void init() {  
  51.         setFocusable(true);     //设置可对焦  
  52.           
  53.         //高亮部分  
  54.         currentPaint = new Paint();  
  55.         currentPaint.setAntiAlias(true);    //设置抗锯齿,让文字美观饱满  
  56.         currentPaint.setTextAlign(Paint.Align.CENTER);//设置文本对齐方式  
  57.           
  58.         //非高亮部分  
  59.         notCurrentPaint = new Paint();  
  60.         notCurrentPaint.setAntiAlias(true);  
  61.         notCurrentPaint.setTextAlign(Paint.Align.CENTER);  
  62.     }  
  63.       
  64.     /** 
  65.      * 绘画歌词 
  66.      */  
  67.     @Override  
  68.     protected void onDraw(Canvas canvas) {  
  69.         super.onDraw(canvas);  
  70.         if(canvas == null) {  
  71.             return;  
  72.         }  
  73.           
  74.         currentPaint.setColor(Color.argb(21025124829));  
  75.         notCurrentPaint.setColor(Color.argb(140255255255));  
  76.           
  77.         currentPaint.setTextSize(24);  
  78.         currentPaint.setTypeface(Typeface.SERIF);  
  79.           
  80.         notCurrentPaint.setTextSize(textSize);  
  81.         notCurrentPaint.setTypeface(Typeface.DEFAULT);  
  82.           
  83.         try {  
  84.             setText("");  
  85.             canvas.drawText(mLrcList.get(index).getLrcStr(), width / 2, height / 2, currentPaint);  
  86.               
  87.             float tempY = height / 2;  
  88.             //画出本句之前的句子  
  89.             for(int i = index - 1; i >= 0; i--) {  
  90.                 //向上推移  
  91.                 tempY = tempY - textHeight;  
  92.                 canvas.drawText(mLrcList.get(i).getLrcStr(), width / 2, tempY, notCurrentPaint);  
  93.             }  
  94.             tempY = height / 2;  
  95.             //画出本句之后的句子  
  96.             for(int i = index + 1; i < mLrcList.size(); i++) {  
  97.                 //往下推移  
  98.                 tempY = tempY + textHeight;  
  99.                 canvas.drawText(mLrcList.get(i).getLrcStr(), width / 2, tempY, notCurrentPaint);  
  100.             }   
  101.         } catch (Exception e) {  
  102.             setText("...木有歌词文件,赶紧去下载...");  
  103.         }  
  104.     }  
  105.   
  106.     /** 
  107.      * 当view大小改变的时候调用的方法 
  108.      */  
  109.     @Override  
  110.     protected void onSizeChanged(int w, int h, int oldw, int oldh) {  
  111.         super.onSizeChanged(w, h, oldw, oldh);  
  112.         this.width = w;  
  113.         this.height = h;  
  114.     }  
  115.   
  116.     public void setIndex(int index) {  
  117.         this.index = index;  
  118.     }  
  119.       
  120. }  

--LrcProcess.java

[java] view plaincopy
  1. package com.wwj.sb.custom;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.File;  
  5. import java.io.FileInputStream;  
  6. import java.io.FileNotFoundException;  
  7. import java.io.IOException;  
  8. import java.io.InputStreamReader;  
  9. import java.util.ArrayList;  
  10. import java.util.List;  
  11.   
  12. import android.util.Xml.Encoding;  
  13. import android.widget.SlidingDrawer;  
  14.   
  15. import com.wwj.sb.domain.LrcContent;  
  16.   
  17. /** 
  18.  * 2013/6/1 
  19.  * @author  wwj 
  20.  *  处理歌词的类 
  21.  */  
  22. public class LrcProcess {  
  23.     private List<LrcContent> lrcList; //List集合存放歌词内容对象  
  24.     private LrcContent mLrcContent;     //声明一个歌词内容对象  
  25.     /** 
  26.      * 无参构造函数用来实例化对象 
  27.      */  
  28.     public LrcProcess() {  
  29.         mLrcContent = new LrcContent();  
  30.         lrcList = new ArrayList<LrcContent>();  
  31.     }  
  32.       
  33.     /** 
  34.      * 读取歌词 
  35.      * @param path 
  36.      * @return 
  37.      */  
  38.     public String readLRC(String path) {  
  39.         //定义一个StringBuilder对象,用来存放歌词内容  
  40.         StringBuilder stringBuilder = new StringBuilder();  
  41.         File f = new File(path.replace(".mp3"".lrc"));  
  42.           
  43.         try {  
  44.             //创建一个文件输入流对象  
  45.             FileInputStream fis = new FileInputStream(f);  
  46.             InputStreamReader isr = new InputStreamReader(fis, "utf-8");  
  47.             BufferedReader br = new BufferedReader(isr);  
  48.             String s = "";  
  49.             while((s = br.readLine()) != null) {  
  50.                 //替换字符  
  51.                 s = s.replace("[""");  
  52.                 s = s.replace("]""@");  
  53.                   
  54.                 //分离“@”字符  
  55.                 String splitLrcData[] = s.split("@");  
  56.                 if(splitLrcData.length > 1) {  
  57.                     mLrcContent.setLrcStr(splitLrcData[1]);  
  58.                       
  59.                     //处理歌词取得歌曲的时间  
  60.                     int lrcTime = time2Str(splitLrcData[0]);  
  61.                       
  62.                     mLrcContent.setLrcTime(lrcTime);  
  63.                       
  64.                     //添加进列表数组  
  65.                     lrcList.add(mLrcContent);  
  66.                       
  67.                     //新创建歌词内容对象  
  68.                     mLrcContent = new LrcContent();  
  69.                 }  
  70.             }  
  71.         } catch (FileNotFoundException e) {  
  72.             e.printStackTrace();  
  73.             stringBuilder.append("木有歌词文件,赶紧去下载!...");  
  74.         } catch (IOException e) {  
  75.             e.printStackTrace();  
  76.             stringBuilder.append("木有读取到歌词哦!");  
  77.         }  
  78.         return stringBuilder.toString();  
  79.     }  
  80.     /** 
  81.      * 解析歌词时间 
  82.      * 歌词内容格式如下: 
  83.      * [00:02.32]陈奕迅 
  84.      * [00:03.43]好久不见 
  85.      * [00:05.22]歌词制作  王涛 
  86.      * @param timeStr 
  87.      * @return 
  88.      */  
  89.     public int time2Str(String timeStr) {  
  90.         timeStr = timeStr.replace(":"".");  
  91.         timeStr = timeStr.replace(".""@");  
  92.           
  93.         String timeData[] = timeStr.split("@"); //将时间分隔成字符串数组  
  94.           
  95.         //分离出分、秒并转换为整型  
  96.         int minute = Integer.parseInt(timeData[0]);  
  97.         int second = Integer.parseInt(timeData[1]);  
  98.         int millisecond = Integer.parseInt(timeData[2]);  
  99.           
  100.         //计算上一行与下一行的时间转换为毫秒数  
  101.         int currentTime = (minute * 60 + second) * 1000 + millisecond * 10;  
  102.         return currentTime;  
  103.     }  
  104.     public List<LrcContent> getLrcList() {  
  105.         return lrcList;  
  106.     }  
  107. }  


加入布局文件:

[html] view plaincopy
  1. <com.wwj.sb.custom.LrcView  
  2.     android:id="@+id/lrcShowView"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="200dip"  
  5.     android:layout_above="@+id/footer_layout"  
  6.     android:layout_below="@+id/header_layout"  
  7.     android:layout_centerHorizontal="true" />  


--在Service.java中的实现,这里就不贴完整的Service类了,主要是如何在Service实现歌词同步的。

声明变量:

[java] view plaincopy
  1. private LrcProcess mLrcProcess; //歌词处理  
  2. private List<LrcContent> lrcList = new ArrayList<LrcContent>(); //存放歌词列表对象  
  3. private int index = 0;          //歌词检索值  

核心实现代码:

[java] view plaincopy
  1. <span style="white-space:pre">  </span>/** 
  2.      * 初始化歌词配置 
  3.      */  
  4.     public void initLrc(){  
  5.         mLrcProcess = new LrcProcess();  
  6.         //读取歌词文件  
  7.         mLrcProcess.readLRC(mp3Infos.get(current).getUrl());  
  8.         //传回处理后的歌词文件  
  9.         lrcList = mLrcProcess.getLrcList();  
  10.         PlayerActivity.lrcView.setmLrcList(lrcList);  
  11.         //切换带动画显示歌词  
  12.         PlayerActivity.lrcView.setAnimation(AnimationUtils.loadAnimation(PlayerService.this,R.anim.alpha_z));  
  13.         handler.post(mRunnable);  
  14.     }  
  15.     Runnable mRunnable = new Runnable() {  
  16.           
  17.         @Override  
  18.         public void run() {  
  19.             PlayerActivity.lrcView.setIndex(lrcIndex());  
  20.             PlayerActivity.lrcView.invalidate();  
  21.             handler.postDelayed(mRunnable, 100);  
  22.         }  
  23.     };  

[java] view plaincopy
  1. /** 
  2.  * 根据时间获取歌词显示的索引值 
  3.  * @return 
  4.  */  
  5. public int lrcIndex() {  
  6.     if(mediaPlayer.isPlaying()) {  
  7.         currentTime = mediaPlayer.getCurrentPosition();  
  8.         duration = mediaPlayer.getDuration();  
  9.     }  
  10.     if(currentTime < duration) {  
  11.         for (int i = 0; i < lrcList.size(); i++) {  
  12.             if (i < lrcList.size() - 1) {  
  13.                 if (currentTime < lrcList.get(i).getLrcTime() && i == 0) {  
  14.                     index = i;  
  15.                 }  
  16.                 if (currentTime > lrcList.get(i).getLrcTime()  
  17.                         && currentTime < lrcList.get(i + 1).getLrcTime()) {  
  18.                     index = i;  
  19.                 }  
  20.             }  
  21.             if (i == lrcList.size() - 1  
  22.                     && currentTime > lrcList.get(i).getLrcTime()) {  
  23.                 index = i;  
  24.             }  
  25.         }  
  26.     }  
  27.     return index;  
  28. }  


其实,小巫还想实现可以拖动歌词来控制播放进度,还有自动搜索歌词等更加完备的实现。
0 0
原创粉丝点击