上一篇写了使用MediaPlayer播放音乐,http://blog.csdn.net/huweigoodboy/article/details/39861539。


代码地址:https://github.com/huweigoodboy/SweetMusicPlayer


现在来将一下加载本地歌词。好了,还是用那张图。


一,从内存卡上匹配歌词

将会从以下路径匹配

1)  SweetMusicPlayer/Lyrics/

2)  歌曲同级目录下

3)  歌曲父级目录/lryics(Lryic加不加s,首字母大小与否又分情况)


LrcContent

package com.huwei.sweetmusicplayer.models;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;}}
LrcProcess

package com.huwei.sweetmusicplayer.models;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.io.UnsupportedEncodingException;import java.util.ArrayList;import java.util.Collections;import java.util.List;import android.util.Log;import com.huwei.sweetmusicplayer.comparator.LrcComparator;import com.huwei.sweetmusicplayer.datamanager.MusicManager;import com.huwei.sweetmusicplayer.util.OnlineLrcUtil;import com.huwei.sweetmusicplayer.util.TimeUtil;public class LrcProcess {private List lrclists;public LrcProcess() {super();lrclists = new ArrayList();lrclists.clear();}public String loadLrc(Song song) {String path = song.getPath();StringBuffer stringBuffer = new StringBuffer();// 得到歌词文件路径String lrcPathString = path.substring(0, path.lastIndexOf("."))+ ".lrc";int index = lrcPathString.lastIndexOf("/");String parentPath;String lrcName;// if(index!=-1){parentPath = lrcPathString.substring(0, index);lrcName = lrcPathString.substring(index);// }File file = new File(lrcPathString);// 匹配SweetMusicPlayer/Lyricsif (!file.exists()) {file = new File(OnlineLrcUtil.getInstance().getLrcPath(song.getTitle(), song.getArtist()));}Log.i("Path", file.getAbsolutePath().toString());// 匹配Lyricsif (!file.exists()) {file = new File(parentPath + "/../" + "Lyrics/" + lrcName);}Log.i("Path", file.getAbsolutePath().toString());// 匹配lyricif (!file.exists()) {file = new File(parentPath + "/../" + "lyric/" + lrcName);}Log.i("Path", file.getAbsolutePath().toString());// 匹配Lyricif (!file.exists()) {file = new File(parentPath + "/../" + "Lyric/" + lrcName);}Log.i("Path", file.getAbsolutePath().toString());// 匹配lyricsif (!file.exists()) {file = new File(parentPath + "/../" + "lyrics/" + lrcName);}Log.i("Path", file.getAbsolutePath().toString());if (!file.exists()) {stringBuffer.append(MusicManager.OperateState.READLRCFILE_FAIL);return stringBuffer.toString();}try {FileInputStream fin = new FileInputStream(file);InputStreamReader isr = new InputStreamReader(fin, "utf-8");BufferedReader br = new BufferedReader(isr);String s;boolean isLrc = false;while ((s = br.readLine()) != null) {// if(isLrc){s = s.replace("[", ""); // 去掉左边括号String lrcData[] = s.split("]");// 这句是歌词if (lrcData[0].matches("^\\d{2}:\\d{2}.\\d+$")) {int len = lrcData.length;int end = lrcData[len - 1].matches("^\\d{2}:\\d{2}.\\d+$") ? len: len - 1;for (int i = 0; i < end; i++) {LrcContent lrcContent = new LrcContent();int lrcTime = TimeUtil.getLrcMillTime(lrcData[i]);lrcContent.setLrcTime(lrcTime);if (lrcData.length == end)lrcContent.setLrcStr(""); // 空白行elselrcContent.setLrcStr(lrcData[len - 1]);lrclists.add(lrcContent);}}}// 按时间排序Collections.sort(lrclists, new LrcComparator());if (lrclists.size() == 0) {stringBuffer.append(MusicManager.OperateState.READLRC_LISTNULL);} else {stringBuffer.append(MusicManager.OperateState.READLRC_SUCCESS);}} catch (FileNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();// stringBuffer.append("未找到歌词文件");} catch (UnsupportedEncodingException e) {// TODO Auto-generated catch blocke.printStackTrace();// stringBuffer.append("不支持的编码");} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();// stringBuffer.append("IO错误");}return stringBuffer.toString();}public List getLrclists() {return lrclists;}}

二,歌词解析

先摘取一段歌词

ti:安静]
[ar:周杰伦]
[al:范特西]
[by:Midas]
[00:03.16] 
[00:04.50]周杰伦-安静
[00:14.50]词:周杰伦 曲:周杰伦 编:钟兴民
[00:25.17]  
[02:27.48][00:27.02]只剩下钢琴陪我谈了一天
[02:32.76][00:32.51]睡着的大提琴 安静的旧旧的
[02:39.60][00:38.67] 
[02:40.74][00:40.48]我想你已表现的非常明白
[02:46.04][00:45.7]我懂我也知道 你没有舍不得
[02:53.23][00:52.53] 
[02:54.04][00:53.76]你说你也会难过我不相信
[03:00.59][01:00.36]牵着你陪着我 也只是曾经
[03:06.63][01:06.24]希望他是真的比我还要爱你
[03:13.29][01:12.96]我才会逼自己离开


每次遍历一行,首先要把“[”替换成" ",去匹配哪些是时间部分,正则匹配“^\\d{2}:\\d{2}.\\d+$”,然后split("]"),得到一个数组data[],最后一个是内容,前面是歌词,遍历数组,装入时间歌词到list。


时间处理:转成毫秒


遍历所有行后,对list按照时间排序。


代码在上面LrcProgress。

三,LrcView控件

分为以下状态:

public static String READLRC_SUCCESS="READLRC_SUCCESS";//读取本地歌词成功
public static String READLRC_LISTNULL="READLRC_LISTNULL";//读取歌词list为null
public static String READLRC_ONLINE="READLRC_ONLINE";//正在从网络加载歌词
public static String READLRCFILE_FAIL="READLRCFILE_FAIL";//读取歌词文件失败
public static String READLRCONLINE_FAIL="READLRCONLINE_FAIL";//从网络加载歌词失败


根据不同的状态绘制不同的内容。

LrcView继承自ScrollView,然后再加一层LinearLayout,歌词绘制在TextView上,按照播放时间滚动,就可以保证当前播放的歌词在屏幕中间了。

关于自定义控件,要注意对onMeasure(),onLayout(),onDraw()比较好的理解,有时候遇到onDraw()不能执行,记得加上setWillNotDraw(false),这里直接继承自ScrollView,就不需要考虑那么多了。


这里需要根据播放时间计算当前播放位置,歌词所在行,然后不同的时候,就去更新歌词界面。



调整歌词进度:

触摸监听时,ACTION_MOVE去绘制歌词进度预览(包括调整到的时间预览),ACTION_UP时调整到对应的进度。



package com.huwei.sweetmusicplayer.ui.widgets;import java.util.List;  import com.huwei.sweetmusicplayer.datamanager.MusicManager;import com.huwei.sweetmusicplayer.models.LrcContent;import com.huwei.sweetmusicplayer.util.TimeUtil; import android.content.Context;import android.content.Intent;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Typeface;import android.os.Handler;import android.os.Message;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.view.View;import android.view.ViewTreeObserver.OnScrollChangedListener;import android.widget.ScrollView;import android.widget.TextView;import android.view.View.OnTouchListener;public class LrcView extends ScrollView implements OnScrollChangedListener,OnTouchListener{private float width;//歌词视图宽度private float height;//歌词视图高度private Paint currentPaint;//当前画笔对象private Paint notCurrentPaint;//非当前画笔对象private final float textHeight=40;//文本高度private final float textSize=36;//高亮文本大小private final float notTextSize=30;//非高亮文本大小private int index;//歌词list集合下标private String lrcState;private LrcTextView lrcTextView;private List lrcLists;private int scrollY;private boolean canDrawLine=false;private int pos=-1; //手指按下后歌词要到的位置private Paint linePaint;private boolean canTouchLrc=false;//是否可以触摸并调整歌词private int count=0;  //绘制加载点的次数private Context mContext;public LrcView(Context context) {this(context,null);// TODO Auto-generated constructor stub}public LrcView(Context context, AttributeSet attrs) {this(context, attrs,0);// TODO Auto-generated constructor stub}public LrcView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);// TODO Auto-generated constructor stubmContext=context;this.setOnTouchListener(this); init(); }public List getLrcLists() {return lrcLists;}public void setLrcLists(List lrcLists) {this.lrcLists = lrcLists;//判断歌词界面是否可以触摸if(lrcLists==null||lrcLists.size()==0)canTouchLrc=false;else canTouchLrc=true;//设置index=-1this.index=-1; LayoutParams params1=new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);lrcTextView=new LrcTextView(this.getContext());lrcTextView.setLayoutParams(params1); this.removeAllViews();this.addView(lrcTextView);}public int getIndex() {return index;}public void setIndex(int index) {//歌曲位置发生变化,而且手指不是调整歌词位置的状态if(this.index!=index&&pos==-1){this.scrollTo(0, (int)(index*textHeight));}this.index = index;} @Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {// TODO Auto-generated method stubsuper.onSizeChanged(w, h, oldw, oldh);this.width=w;this.height=h;}public int getIndexByLrcTime(int currentTime){for(int i=0;i=6) count=0;        canvas.drawText(drawContentStr, width/2, tempY, notCurrentPaint);             handler.sendEmptyMessageDelayed(1, 500);    return;    }else if(MusicManager.OperateState.READLRCONLINE_FAIL.equals(lrcState)){    canvas.drawText("从网络加载歌词失败", width/2, tempY, notCurrentPaint);    return;    }        }@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {// TODO Auto-generated method stubsuper.onMeasure(widthMeasureSpec, heightMeasureSpec);heightMeasureSpec=(int) (height+textHeight*(lrcLists.size()-1));setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);}};@Overrideprotected void onDraw(Canvas canvas) {// TODO Auto-generated method stubsuper.onDraw(canvas);if(canDrawLine){canvas.drawLine(0, scrollY+height/2, width, scrollY+height/2, linePaint);canvas.drawText(TimeUtil.toTime(lrcLists.get(pos).getLrcTime()), 42, scrollY+height/2-2, linePaint);}}private void init(){setFocusable(true);//设置该控件可以有焦点this.setWillNotDraw(false);  //高亮歌词部分currentPaint=new Paint();currentPaint.setAntiAlias(true);//设置抗锯齿currentPaint.setTextAlign(Paint.Align.CENTER);//设置文本居中//非高亮歌词部分notCurrentPaint=new Paint();notCurrentPaint.setAntiAlias(true);notCurrentPaint.setTextAlign(Paint.Align.CENTER);//linePaint=new Paint();linePaint.setAntiAlias(true);linePaint.setTextAlign(Paint.Align.CENTER);//设置画笔颜色currentPaint.setColor(Color.argb(210, 251, 248, 29));      notCurrentPaint.setColor(Color.argb(140, 255, 255, 255));      linePaint.setColor(Color.RED);        currentPaint.setTextSize(textSize);    currentPaint.setTypeface(Typeface.SERIF);        notCurrentPaint.setTextSize(notTextSize);    notCurrentPaint.setTypeface(Typeface.DEFAULT);        linePaint.setTextSize(textSize);    linePaint.setTypeface(Typeface.SERIF);    }@Overridepublic void invalidate() {// TODO Auto-generated method stubsuper.invalidate(); lrcTextView.invalidate();}@Overridepublic void onScrollChanged() {// TODO Auto-generated method stub }@Overridepublic boolean onTouch(View v, MotionEvent event) {// TODO Auto-generated method stub//界面不能被触摸if(!canTouchLrc)  return true;switch(event.getAction()){case MotionEvent.ACTION_MOVE:scrollY=this.getScrollY();pos=(int) (this.getScrollY()/textHeight);canDrawLine=true;this.invalidate();Log.i("LrcView", "ACTION_DOWN");break;caseMotionEvent.ACTION_UP:MusicManager.getInstance().setProgress(lrcLists.get(pos).getLrcTime());canDrawLine=false;pos=-1;this.invalidate();break;}return false;}private Handler handler=new Handler(){@Overridepublic void handleMessage(Message msg) {// TODO Auto-generated method stubinvalidate();}};}


下一篇智能匹配在线歌词: http://blog.csdn.net/huweigoodboy/article/details/39878063


更多相关文章

  1. ListView属性及方法android
  2. 【Android学习笔记】Android中Intent的应用方法探索
  3. 一.GLSurfaceView介绍
  4. Android(安卓)增加预置的APN信息
  5. (转载) Android(安卓)RecyclerView 使用完全解析 体验艺术般的控件
  6. Android利用AChartEngine绘制图表
  7. Android(安卓)手势锁/锁屏/Pin解锁,一种精简高大上且实用的手势锁
  8. ContentProvider简单用法
  9. Android(安卓)RoboGuice 使用指南(8):Provider Bindings

随机推荐

  1. Java super关键字(android中常见)
  2. LBE 安全大师支持android 4.4注入分析
  3. android中动画效果编程详解
  4. ionic打包apk时报错No resource identifi
  5. Android 怎样获得手机信息(二)
  6. Android分辨率自适应
  7. Android中文API(146) —— Display
  8. Android(安卓)电话的反射调用机制实现静
  9. Android Activity切换动画详解及实例
  10. Android手机中获取手机号码和运营商信息