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

               

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

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

-----前话

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

-----主题

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

     要的效果如下:

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

----实现过程

1. 建立歌词内容实体类

2. 自定义View

3. 加入布局文件

4. 编写歌词处理类

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


----代码实现

--LrcContent.java

package com.wwj.sb.domain;/** * 2013/6/1 * @author wwj * 歌词实体类 */public class LrcContent private String lrcStr; //歌词内容 private int lrcTime; //歌词当前时间 public String getLrcStr() {  return lrcStr; } public void setLrcStr(String lrcStr) {  this.lrcStr = lrcStr; } public int getLrcTime() {  return lrcTime; } public void setLrcTime(int lrcTime) {  this.lrcTime = lrcTime; }}


--LrcView.java

package com.wwj.sb.custom;import java.util.ArrayList;import java.util.List;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 com.wwj.sb.domain.LrcContent;/** * 自定义绘画歌词,产生滚动效果 * @author wwj * */public class LrcView extends android.widget.TextView private float width;  //歌词视图宽度 private float height;  //歌词视图高度 private Paint currentPaint; //当前画笔对象 private Paint notCurrentPaint; //非当前画笔对象 private float textHeight = 25//文本高度 private float textSize = 18;  //文本大小 private int index = 0;  //list集合下标   private List<LrcContent> mLrcList = new ArrayList<LrcContent>();  public void setmLrcList(List<LrcContent> mLrcList) {  this.mLrcList = mLrcList; } 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(24);  currentPaint.setTypeface(Typeface.SERIF);    notCurrentPaint.setTextSize(textSize);  notCurrentPaint.setTypeface(Typeface.DEFAULT);    try {   setText("");   canvas.drawText(mLrcList.get(index).getLrcStr(), width / 2, height / 2, currentPaint);      float tempY = height / 2;   //画出本句之前的句子   for(int i = index - 1; i >= 0; i--) {    //向上推移    tempY = tempY - textHeight;    canvas.drawText(mLrcList.get(i).getLrcStr(), width / 2, tempY, notCurrentPaint);   }   tempY = height / 2;   //画出本句之后的句子   for(int i = index + 1; i < mLrcList.size(); i++) {    //往下推移    tempY = tempY + textHeight;    canvas.drawText(mLrcList.get(i).getLrcStr(), width / 2, tempY, notCurrentPaint);   }   } catch (Exception e) {   setText("...木有歌词文件,赶紧去下载...");  } } /**  * 当view大小改变的时候调用的方法  */ @Override 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; } }

--LrcProcess.java

package com.wwj.sb.custom;import java.io.BufferedReader;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;import java.io.InputStreamReader;import java.util.ArrayList;import java.util.List;import android.util.Xml.Encoding;import android.widget.SlidingDrawer;import com.wwj.sb.domain.LrcContent;/** * 2013/6/1 * @author wwj * 处理歌词的类 */public class LrcProcess private List<LrcContent> lrcList; //List集合存放歌词内容对象 private LrcContent mLrcContent;  //声明一个歌词内容对象 /**  * 无参构造函数用来实例化对象  */ public LrcProcess() {  mLrcContent = new LrcContent();  lrcList = new ArrayList<LrcContent>(); }  /**  * 读取歌词  * @param path  * @return  */ public String readLRC(String path) {  //定义一个StringBuilder对象,用来存放歌词内容  StringBuilder stringBuilder = new StringBuilder();  File f = new File(path.replace(".mp3", ".lrc"));    try {   //创建一个文件输入流对象   FileInputStream fis = new FileInputStream(f);   InputStreamReader isr = new InputStreamReader(fis, "utf-8");   BufferedReader br = new BufferedReader(isr);   String s = "";   while((s = br.readLine()) != null) {    //替换字符    s = s.replace("[", "");    s = s.replace("]", "@");        //分离“@”字符    String splitLrcData[] = s.split("@");    if(splitLrcData.length > 1) {     mLrcContent.setLrcStr(splitLrcData[1]);          //处理歌词取得歌曲的时间     int lrcTime = time2Str(splitLrcData[0]);          mLrcContent.setLrcTime(lrcTime);          //添加进列表数组     lrcList.add(mLrcContent);          //新创建歌词内容对象     mLrcContent = new LrcContent();    }   }  } catch (FileNotFoundException e) {   e.printStackTrace();   stringBuilder.append("木有歌词文件,赶紧去下载!...");  } catch (IOException e) {   e.printStackTrace();   stringBuilder.append("木有读取到歌词哦!");  }  return stringBuilder.toString(); } /**  * 解析歌词时间  * 歌词内容格式如下:  * [00:02.32]陈奕迅  * [00:03.43]好久不见  * [00:05.22]歌词制作  王涛  * @param timeStr  * @return  */ public int time2Str(String timeStr) {  timeStr = timeStr.replace(":", ".");  timeStr = timeStr.replace(".", "@");    String timeData[] = timeStr.split("@"); //将时间分隔成字符串数组    //分离出分、秒并转换为整型  int minute = Integer.parseInt(timeData[0]);  int second = Integer.parseInt(timeData[1]);  int millisecond = Integer.parseInt(timeData[2]);    //计算上一行与下一行的时间转换为毫秒数  int currentTime = (minute * 60 + second) * 1000 + millisecond * 10;  return currentTime; } public List<LrcContent> getLrcList() {  return lrcList; }}


加入布局文件:

 <com.wwj.sb.custom.LrcView     android:id="@+id/lrcShowView"     android:layout_width="match_parent"     android:layout_height="200dip"     android:layout_above="@+id/footer_layout"     android:layout_below="@+id/header_layout"     android:layout_centerHorizontal="true" />


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

声明变量:

private LrcProcess mLrcProcess; //歌词处理private List<LrcContent> lrcList = new ArrayList<LrcContent>(); //存放歌词列表对象private int index = 0;   //歌词检索值

核心实现代码:

 /**  * 初始化歌词配置  */ public void initLrc(){  mLrcProcess = new LrcProcess();  //读取歌词文件  mLrcProcess.readLRC(mp3Infos.get(current).getUrl());  //传回处理后的歌词文件  lrcList = mLrcProcess.getLrcList();  PlayerActivity.lrcView.setmLrcList(lrcList);  //切换带动画显示歌词  PlayerActivity.lrcView.setAnimation(AnimationUtils.loadAnimation(PlayerService.this,R.anim.alpha_z));  handler.post(mRunnable); } Runnable mRunnable = new Runnable() {    @Override  public void run() {   PlayerActivity.lrcView.setIndex(lrcIndex());   PlayerActivity.lrcView.invalidate();   handler.postDelayed(mRunnable, 100);  } };

 /**  * 根据时间获取歌词显示的索引值  * @return  */ public int lrcIndex() {  if(mediaPlayer.isPlaying()) {   currentTime = mediaPlayer.getCurrentPosition();   duration = mediaPlayer.getDuration();  }  if(currentTime < duration) {   for (int i = 0; i < lrcList.size(); i++) {    if (i < lrcList.size() - 1) {     if (currentTime < lrcList.get(i).getLrcTime() && i == 0) {      index = i;     }     if (currentTime > lrcList.get(i).getLrcTime()       && currentTime < lrcList.get(i + 1).getLrcTime()) {      index = i;     }    }    if (i == lrcList.size() - 1      && currentTime > lrcList.get(i).getLrcTime()) {     index = i;    }   }  }  return index; }


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


           

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow