分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow
也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!
Android应用开发--MP3音乐播放器滚动歌词实现
2013年6月2日 简、美音乐播放器开发记录
-----前话
有网友给我博客评论说,让我借鉴好的Android代码,代码贴出来的时候最好整体先看一下。其实小巫也有参考过别人的代码,主要是具体看某一个功能是怎么实现的,但是因为开发的思路不一样,只能说自己去写一些符合自己思路的代码。编写代码过程中,或多或少有纰漏之处,但基本上能实现功能就行了。小巫的功底还不够,不具备很强的重构代码的能力,一直都是以最直观的想法来编程,并没有太过关注性能的优化啥的,因为我也没发现自己开发的这款音乐播放器用起来不爽。不过,小巫会一直学习的,努力提升自己的编程水平,争取生产出优美的代码供朋友们参考。
-----主题
这篇博客的主题是:“滚动歌词的实现”
要的效果如下:
----实现过程
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 mLrcList = new ArrayList(); public void setmLrcList(List 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; } }
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 lrcList; //List集合存放歌词内容对象 private LrcContent mLrcContent; //声明一个歌词内容对象 /** * 无参构造函数用来实例化对象 */ public LrcProcess() { mLrcContent = new LrcContent(); lrcList = new ArrayList(); } /** * 读取歌词 * @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 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 lrcList = new ArrayList(); //存放歌词列表对象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; }