该文档讲述在android中如何自定义歌词控件同步显示歌词,文档讲述歌词控件用法,程序中所需要的也只有2个类,一个歌词对象,一个歌词控件,兼容性很强。无须配置特别的xml文件,简单易用
Android自定义歌词同步控件
Android音乐播放器中,播放音乐的类(即MediaPlayer)在播放音乐的时候,通过MediaPlayer的getCurrentPosition方法可以得到当前音乐播放的流进度,通过getDuration可以得到当前音乐总的流大小。因此,我们可以通过这两个方法来判断同步的音乐歌词播放进度。下面,该文档将为大家实现歌词同步,其他音乐播放的东西一概不涉及。
歌词同步相关两个类: SongLyric(歌词对象) 歌词对象实例化即可使用,但必须保证该歌词对象验证通过,即歌词文件存在,切正确实例化。
LyricView(Android自定义歌词控件) 该歌词控件不可以写在xml配置文件中,必须使用一个layout布局控件存放,使用的时候先从Activity中得到layout,然后再将该歌词控件通过layout的getContext的参数实例化,最后添加到layout中,并且将对应的歌词对象SongLyric设置到歌词控件中。最后,歌词控件要做到与音乐同步的效果,还得时时刷新歌词控件,这样就有了歌词同步以及滚动的效果。具体实现方法下面讲到,先看看这两个类源码:
SongLyric类,该对象和网上大部分歌词对象一样,这里为了和歌词控件LyricView配套,
该文档讲述在android中如何自定义歌词控件同步显示歌词,文档讲述歌词控件用法,程序中所需要的也只有2个类,一个歌词对象,一个歌词控件,兼容性很强。无须配置特别的xml文件,简单易用
// 歌手名 private String artist = ""; // 专辑名 private String album = ""; // 偏移时间 private long offset = 0; // 最大时间 private long maxTime = 0; // 歌词内容 private Map<Long, String> lrcs = new HashMap<Long, String>(); // 验证是否通过 private boolean valid = false; public SongLyric(String url) { File file = new File(url); if (file.exists()) { try { // 构建读取器 BufferedReader br = new BufferedReader(new InputStreamReader( new FileInputStream(file), "gbk")); String line = null; while ((line = br.readLine()) != null) { dealLine(line); } valid = true; } catch (Exception e) { System.out.println("Exception"); } } } public String getTitle() { return this.title; } public String getArtist() { return this.artist; } public String getAlbum() { return this.album; } public boolean isValid() {
该文档讲述在android中如何自定义歌词控件同步显示歌词,文档讲述歌词控件用法,程序中所需要的也只有2个类,一个歌词对象,一个歌词控件,兼容性很强。无须配置特别的xml文件,简单易用
return this.valid; } public long getMaxTime() { return this.maxTime; } public void setMaxTime(long time) { this.maxTime = time; } /** * 获取该时间应当显示的歌词 * * @param ls * @return */ public String get(long ls) { long time = ls + offset; Long curr = -1l; for (Long l : lrcs.keySet()) { curr = l > time ? curr : l < curr ? curr : l; } return lrcs.get(curr); } /** * 获取该时间所要显示的歌词初始时
间的索引 * * @param ls * @return */ public int getIndex(long ls) { Long[] ts = getAllTimes(); for (int i = 0; i < ts.length - 1; i++) { if (ls + offset >= ts[i] && ls + offset < ts[i + 1]) { return i; } } return ts.length - 1; } /** * 获取该时间与歌词初始时间差值
该文档讲述在android中如何自定义歌词控件同步显示歌词,文档讲述歌词控件用法,程序中所需要的也只有2个类,一个歌词对象,一个歌词控件,兼容性很强。无须配置特别的xml文件,简单易用
* * @param ls * @return */ public int getOffset(long ls) { Long[] ts = getAllTimes(); int index = getIndex(ls); if (index < ts.length && index >= 0) { return (int) (ls + offset - ts[index]); } return 0; } /** * 获取该时间段播放的歌词共播放时间 * * @param ls * @return */ public int getNextTime(long ls) { Long[] ts = getAllTimes(); int index = getIndex(ls); if (index < ts.length - 1) { return (int) (ts[index + 1] - ts[index]); } return 0; } /** * 处理歌词行 * * @param line */ private void dealLine(String line) { if (line != null && !line.equals("")) { if (line.startsWith("[ti:")) {// 标题 title = line.substring(4, line.length() - 1); } else if (line.startsWith("[ar:")) {// 歌手 artist = line.substring(4, line.length() - 1); } else if (line.startsWith("[al:")) {// 专辑 album = line.substring(4, line.length() - 1); } else if (line.startsWith("[offset:")) {// 专辑 offset = Long.parseLong(line.substring(8, line.length() - 1)); } else {
该文档讲述在android中如何自定义歌词控件同步显示歌词,文档讲述歌词控件用法,程序中所需要的也只有2个类,一个歌词对象,一个歌词控件,兼容性很强。无须配置特别的xml文件,简单易用
// 该行歌词内容 Pattern ptn = http://pile("\\[(\\d{2}:\\d{2}\\.\\d{2})\\]"); Matcher mth = ptn.matcher(line); while (mth.find()) { // 得到时间点 long time = strToLong(mth.group(1)); // 得到时间点后的内容 String[] str = ptn.split(line); String lrc = str.length > 0 ? str[str.length - 1] : ""; lrcs.put(time, lrc); maxTime = maxTime > time ? maxTime : time; } } } } /** * 将 00:00.00 格式的歌词时间转换为 long * * @param timeStr * @return */ public static long strToLong(String timeStr) { String[] s = timeStr.split(":"); int min = Integer.parseInt(s[0]); String[] ss = s[1].split("\\."); int sec = Integer.parseInt(ss[0]); int mill = Integer.parseInt(ss[1]); return min * 60 * 1000 + sec * 1000 + mill * 10; } /** * 处理毫秒数,以 00:00 的方式返回 * * @param ts * @return */ public static String longToString(long ts) { int time = (int) ts / 1000; int ms = time % 60; int ss = time / 60; ss = ss > 99 ? 99 : ss; StringBuffer str = new StringBuffer(); str.append(ss < 10 ? "0" + ss + ":" : ss + ":");
该文档讲述在android中如何自定义歌词控件同步显示歌词,文档讲述歌词控件用法,程序中所需要的也只有2个类,一个歌词对象,一个歌词控件,兼容性很强。无须配置特别的xml文件,简单易用
LyricView控件源码(该类为Android自定义控件,可以看到构造方法只有一个,需得传一个
该文档讲述在android中如何自定义歌词控件同步显示歌词,文档讲述歌词控件用法,程序中所需要的也只有2个类,一个歌词对象,一个歌词控件,兼容性很强。无须配置特别的xml文件,简单易用
* */ public final class LyricView extends View { // 歌词对象 private SongLyric lrc = null; // 当前播放时间 private long time = 0l; // 字体画笔 private Paint fontPaint = null; // 当前歌词字体画笔 private Paint lrcPaint = null; // 字体颜色 private int fontColor = Color.WHITE; // 当前歌词字体颜色 private int lrcColor = Color.RED; // 字体大小 private int fontSize = 14; public LyricView(Context context) { super(context); } /** * 设置歌词对象 * * @param lrc */ public void setLyric(SongLyric lrc) { this.lrc = lrc; } /** * 设置当前时间 * * @param ms */ public void setTime(long ms) { this.time = ms; } /** * 设置歌词字体颜色 *
该文档讲述在android中如何自定义歌词控件同步显示歌词,文档讲述歌词控件用法,程序中所需要的也只有2个类,一个歌词对象,一个歌词控件,兼容性很强。无须配置特别的xml文件,简单易用
* @param color */ public void setFontColor(int color) { this.fontColor = color; } /** * 设置当前歌词字体颜色 * * @param color */ public void setLyricColor(int color) { this.lrcColor = color; } /** * 设置字体大小 * * @param size */ public void setFontSize(int size) { this.fontSize = size; } /** * 重绘视图 */ @Override protected void onDraw(Canvas c) { super.onDraw(c); if (lrc != null) { try { if (fontPaint == null) { fontPaint = new Paint(); } if (lrcPaint == null) { lrcPaint = new Paint(); } fontPaint.setColor(fontColor); fontPaint.setTextSize(fontSize); lrcPaint.setColor(lrcColor); lrcPaint.setTextSize(fontSize); // 获取当前要播放歌词的索引 int cIndex = lrc.getIndex(time);
该文档讲述在android中如何自定义歌词控件同步显示歌词,文档讲述歌词控件用法,程序中所需要的也只有2个类,一个歌词对象,一个歌词控件,兼容性很强。无须配置特别的xml文件,简单易用
为了大家更了解该歌词控件,下面有一个小小的例子,该例子只是模拟了MediaPlayer播放显示的歌词同步效果,只需要用一个handler不停更新LyricView的setTime方法既可以由歌
该文档讲述在android中如何自定义歌词控件同步显示歌词,文档讲述歌词控件用法,程序中所需要的也只有2个类,一个歌词对象,一个歌词控件,兼容性很强。无须配置特别的xml文件,简单易用
private SongLyric lrc; // 音乐进度滚动条 private SeekBar skOpera; // 歌词控件 private LyricView vwLrc; // 相关变量(isRelase 为是否用户拖动滚动条,end 为是否退出程序) private boolean isRelase = false, end = false; // 模拟的音乐进度毫秒值 private long time = 0; /** * 注意, Activity 为模拟的效果, 该 真正使
用的时候将 MediaPlayer 的 getCurrentPosition * 传给歌词控件的 setTime 中,刷新的时候只用该方法即可。 */ // 刷新歌词控件的 handler private Handler hand = new Handler() { public void handleMessage(Message msg) { skOpera.setProgress((int) ((time / (float) lrc.getMaxTime()) * 100)); // 设置歌词当前播放时间 vwLrc.setTime(time); vwLrc.postInvalidate(); setTitle(SongLyric.longToString((int) time) + "/" + SongLyric.longToString((int) lrc.getMaxTime())); } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(http://yout.main); // 实例化歌词对象 lrc = new SongLyric("sdcard/Music/fc.lrc"); // 设置歌词播放总时间,假如该歌词要播放 18W 毫秒,即 3 分钟 lrc.setMaxTime(180000); skOpera = (SeekBar) findViewById(R.id.skOpera); // 用 LinearLayout 存放歌词控件 LinearLayout layout = (LinearLayout) findViewById(R.id.lyoutView); vwLrc = new LyricView(layout.getContext()); vwLrc.setBackgroundColor(Color.GREEN); layout.addView(vwLrc); // 为歌词控件初始化,设置歌词
该文档讲述在android中如何自定义歌词控件同步显示歌词,文档讲述歌词控件用法,程序中所需要的也只有2个类,一个歌词对象,一个歌词控件,兼容性很强。无须配置特别的xml文件,简单易用
vwLrc.setLyric(lrc); // 模拟定位播放效果 skOpera.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { public void onStopTrackingTouch(SeekBar seekBar) { isRelase = false; } public void onStartTrackingTouch(SeekBar seekBar) { isRelase = true; } public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (fromUser) { time = lrc.getMaxTime() * skOpera.getProgress() / 100; } } }); // 该线程时时更新歌词控件 new Thread() { public void run() { while (!end) { hand.sendMessage(hand.obtainMessage()); try { sleep(100); } catch (Exception e) { } } }; }.start(); // 该线程模拟音乐播放,控制歌词进度 new Thread() { public void run() { long max = lrc.getMaxTime(); while (!end) { if (time < max) time += 10; try { sleep(10); } catch (Exception e) { }
该文档讲述在android中如何自定义歌词控件同步显示歌词,文档讲述歌词控件用法,程序中所需要的也只有2个类,一个歌词对象,一个歌词控件,兼容性很强。无须配置特别的xml文件,简单易用
很简单的例子,唯一不足的就是没有真正用到MediaPlayer这个类,不过后来我在做音乐播放器的时候还是用到了,看看下面的效果(该效果非上面例子的效果,而是我做的播放器主界面效果….虽然不是很好看):
该文档讲述在android中如何自定义歌词控件同步显示歌词,文档讲述歌词控件用法,程序中所需要的也只有2个类,一个歌词对象,一个歌词控件,兼容性很强。无须配置特别的xml文件,简单易用