(第一个文档 有问题处请大家多多包含)

在Musicplayer中,如何使歌词与歌曲同步显示?

这其实很简单。

我们可以下载一个lrc歌词文件,打开该文件我们可以发现其实lrc文件中格式是很规范的
lrc文件如下:

如何使歌词与歌曲同步显示,关键点就在于lrc文件显示的格式。上图我们发现lrc歌词文件是分两部分组成  左边是歌词播放的时间,右边是歌词内容。

我们可以创建一个集合来存放该信息,该集合的存放数据类型为lrc内容的实体类且该类中属性分为歌词时间与歌词内容。同时在使用MediaPlayer类来播放音频文件时,有一个getCurrentPosition()方法获取当前播放时间。

因为通过该方法获取的时间是毫秒单位,所以我们在截取lrc文件中时间的时候先转换为毫秒,在与当前时间对比就可以知道当前时间所对应的歌词内容了。话不多说,

代码如下:

首先我们需要一个Music工具类用来存放歌词信息的实体类 与 读取歌词方法类.代码如下:

MusicUtils.java:

package com.example.test;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;

public class MusicUtils {

public static class MusicInfos {
private String LrcContent;
private int LrcTime;

public String getLrcContent() {
return LrcContent;
}

public void setLrcContent(String lrcContent) {
LrcContent = lrcContent;
}

public int getLrcTime() {
return LrcTime;
}

public void setLrcTime(int lrcTime) {
LrcTime = lrcTime;
}

}

public static class ReadLrc {
MusicInfos musicInfos = null;
ArrayList<MusicInfos> LrcList = null;

public ReadLrc() {
musicInfos = new MusicInfos();
LrcList = new ArrayList<MusicUtils.MusicInfos>();
}

public void Read(String file) throws IOException {
File f = new File(file);
FileInputStream fis = new FileInputStream(f);
InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
BufferedReader br = new BufferedReader(isr);
String s = null;
StringBuffer sb = null;
while ((s = br.readLine()) != null) {
s = s.replace("[", "");
s = s.replace("]", "@");
String lrc_data[] = s.split("@");
if (lrc_data.length > 1) {
String lrcContent = lrc_data[1];
String lrcTime = lrc_data[0];
musicInfos.setLrcContent(lrcContent);
int time = LrcTime(lrcTime);
musicInfos.setLrcTime(time);
LrcList.add(musicInfos);
musicInfos = new MusicInfos();
}
}
br.close();
isr.close();
}

public int LrcTime(String lrcTime) {
lrcTime = lrcTime.replace(":", ".");
lrcTime = lrcTime.replace(".", "@");
String[] lrc_time = lrcTime.split("@");
String min = lrc_time[0];
String seconds = lrc_time[1];
String perseconds = lrc_time[2];
int currentTime = ((Integer.parseInt(min) * 60 + Integer
.parseInt(seconds)) * 1000 + Integer.parseInt(perseconds) * 10);
return currentTime;

}

public ArrayList<MusicInfos> getLrcList() {
return LrcList;
}
}

}

//在MusicUtils.class中我们创建两个静态内部类。在ReadLrc.class中使用Read方法来读取lrc文件。并且通过replace把lrc文件中"[" 换为空字符 把“]”换为“@”。

目的是为了通过@截取时间与歌词内容两部分 (你也可以不用替换"]"根据个人喜欢) 再把截取的内容放入 集合中。这里我们通过LrcTime()方法来把时间单位转换

为毫秒。

同时我们需要自定义视图空间来动态显示歌词内容,代码如下:

LrcView:

package com.example.test;

import java.util.ArrayList;

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 android.util.Log;
import android.widget.TextView;

import com.example.test.MusicUtils.MusicInfos;

public class LrcView extends TextView {
private Paint CurrentPaint;
private ArrayList<MusicInfos> LrcContentList = new ArrayList<MusicUtils.MusicInfos>();

private Paint NotCurrentPaint;
private int index;
private float width;
private float heigth;
private float textSize = 20;
private float textHeight = 30;
private String tag = "tag";

public LrcView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);

init();
}

public LrcView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}

public LrcView(Context context) {
super(context);
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);

}

public void setLrcContent(ArrayList<MusicInfos> LrcContentList) {
this.LrcContentList = LrcContentList;

}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (canvas == null) {
return;
}
CurrentPaint.setColor(Color.YELLOW);
CurrentPaint.setTextSize(textSize);
CurrentPaint.setTypeface(Typeface.SERIF); // 设置字体(衬线)
NotCurrentPaint.setColor(Color.BLUE);
NotCurrentPaint.setTextSize(textSize);
NotCurrentPaint.setTypeface(Typeface.SERIF);

try {
canvas.drawText(LrcContentList.get(index).getLrcContent(),
width / 2, heigth / 2, CurrentPaint);

float mheight = heigth / 2;
for (int i = index - 1; i >= 0; i--) {
mheight = mheight - textHeight;
canvas.drawText(LrcContentList.get(i).getLrcContent(),
width / 2, mheight, NotCurrentPaint);
}

mheight = heigth / 2;
for (int i = index + 1; i < LrcContentList.size(); i++) {
mheight = mheight + textHeight;
canvas.drawText(LrcContentList.get(i).getLrcContent(),
width / 2, mheight, NotCurrentPaint);
}
} catch (Exception e) {
e.printStackTrace();
}

}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
this.heigth = h;
this.width = w;

}

public void setIndex(int Index) {
this.index = Index;
}

}

//通过setIndex()方法来从外部获取索引位置。使在onDraw()方法中通过index来画图(歌词)

最后我们需要一个MainActivity来实现这些方法。

MainActivity.class:

package com.example.test;

import java.io.IOException;
import java.util.ArrayList;

import android.app.Activity;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

import com.example.test.MusicUtils.MusicInfos;
import com.example.test.MusicUtils.ReadLrc;

public class MainActivity extends Activity {

MediaPlayer mediaPlayer = null;
ReadLrc readLrc = null;
Button btnPlay = null;
LrcView tvLrc = null;
ArrayList<MusicInfos> Lrcinfos = new ArrayList<MusicUtils.MusicInfos>();
private int index = 0;
private int currentTime = 0;
private int countTime = 0;
private String tag = "tag";

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();

try {
readLrc.Read("sdcard/yaoyuandeta.lrc");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Lrcinfos = readLrc.getLrcList();
tvLrc.setLrcContent(Lrcinfos);
mHandler.post(runnable);
btnPlay.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {

play();
}
});

}

public void play() {
try {
Log.i(tag, "play1");
mediaPlayer.reset();
Log.i(tag, "play2");
mediaPlayer.setDataSource("sdcard/yaoyuandeta.mp3");
Log.i(tag, "play3");
mediaPlayer.prepare();
Log.i(tag, "play4");
mediaPlayer.start();
mediaPlayer.setLooping(true);

} catch (IllegalStateException e) {
Log.i(tag, "error1");
e.printStackTrace();
} catch (IllegalArgumentException e) {
Log.i(tag, "error2");
e.printStackTrace();
} catch (SecurityException e) {
Log.i(tag, "error3");
e.printStackTrace();
} catch (IOException e) {
Log.i(tag, "error4");
e.printStackTrace();
}
}

Handler mHandler = new Handler();
Runnable runnable = new Runnable() {

@Override
public void run() {
tvLrc.setIndex(Index());
tvLrc.invalidate();
tvLrc.postDelayed(runnable, 100);
}
};

public int Index() {
if (mediaPlayer.isPlaying()) {
currentTime = mediaPlayer.getCurrentPosition();
countTime = mediaPlayer.getDuration();
}

if (currentTime < countTime) {
for (int i = 0; i < Lrcinfos.size(); i++) {
if (i < Lrcinfos.size() - 1) {
if (currentTime > Lrcinfos.get(i).getLrcTime() && i == 0) {
index = i;
}
if (currentTime > Lrcinfos.get(i).getLrcTime()
&& currentTime <= Lrcinfos.get(i + 1).getLrcTime()) {
index = i;
}
}
if (currentTime == Lrcinfos.size() - 1
&& currentTime < Lrcinfos.get(i).getLrcTime()) {
index = i;
}
}
}
return index;
}

private void init() {

mediaPlayer = new MediaPlayer();
readLrc = new ReadLrc();
btnPlay = (Button) findViewById(R.id.btnStart);
tvLrc = (LrcView) findViewById(R.id.tv);
}

@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
Log.i(tag, "destroy");
mediaPlayer.stop();

}

}

//这里我们不进行遍历sdcard或者通过MediaStore来获取音频文件信息,直接通过路径来获取一个示例。我们通过线程动态的向setIndex()方法中传入index值,来实时同步歌词与音乐。

xml文件如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

<Button
        android:id="@+id/btnStart"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="播放音乐" />

<com.example.test.LrcView
        android:id="@+id/tv"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    </com.example.test.LrcView>

</LinearLayout>

Lrc文件与音乐的同步显示相关推荐

  1. android 歌词同步 换行,HTML5音乐播放器同步显示歌词

    歌词文件的格式 实现之前,当然得了解一下歌词文件的格式了.常规歌词文件的格式基本是一句一行,每行由两部分组成,前面是中括号括起来的时间轴,后面紧跟歌词,像下面这样:[ti:记兰生襄铃] [ar:HIT ...

  2. 《新lrc播放器2》-iPhone上可以显示lrc歌词的播放器可以在播放mp3文件时显示lrc文件中的歌词的播放器

    https://apps.apple.com/cn/app/%E6%96%B0lrc%E6%92%AD%E6%94%BE%E5%99%A82/id1535214306 以前,在iPhone上播放lrc ...

  3. Mac上如何显示本地lrc文件歌词——lrc播放器——《Super LRC Player》

    前不久,用QQ音乐背单词,背了一阵子,很郁闷,因为:1.长的歌词行显示不全:2.歌词自动从网上抓取,不是自己想要的本地lrc文件内容: 于是,有了想法:自己开发一款能够播放本地mp3和lrc的mp3播 ...

  4. 网页中LRC歌词同步显示

    <html><head> <title>音乐歌词同步测试</title> <style> <!-- .div { width:460p ...

  5. html怎么读取lrc文件,lrc文件怎么打开?lrc是什么文件?

    lrc文件怎么打开?lrc是什么文件? lrc是歌词 文件的扩展名,一般用记事本打开. 关于lrc是什么文件?lrc是英文lyric(歌词)的缩写,被用做歌词文件的扩展名.以lrc为扩展名的歌词文件可 ...

  6. 云服务器文件同步,Windows 8:本地文件与云服务器同步

    4月20日消息,上周,Windows 8 Miletone 1开始通过FTP在网络上流传,也就是所谓的Build 7850版本.去年年末时,该版本的Windows 8由微软合作伙伴手中流出.Milet ...

  7. 用批处理整理百度MP3上歌曲排行榜MP3及LRC文件的批量下载链接地址(含图文教程)

    http://bbs.wuyou.com/viewthread.php?tid=192322 本文结构如下: 一.缘起:问题的提出 二.试探:徒劳而返 三.峰回路转:芝麻!开门! 四.万事俱备:xml ...

  8. android简单歌词,《Android_MP3播放器(初学简单版_歌名、歌手、歌词同步显示)》.doc...

    Android_MP3播放器(初学简单版) --乐拐 这是我学习Android以来的第二个程序--MP3播放器(简单版),我的第一个程序是比较实用的通讯录(文档地址是:/view/d013f64fc8 ...

  9. 基于stm32和RDA5851S蓝牙模块的歌名歌手同步显示

    整理东西整理出了几块RDA5851S模块 本着物尽其用的原则,我查了一下相关资料,发现是在车载上用的,还可以进行AT控制 看到这里我觉得还好,因为这种可以AT控制的蓝牙模块还是比较常见的, 本着试一试 ...

  10. fread读取整个文件_qt如何实现大文件的加载和显示

    最近研究了下如何用qt的原生控件来加载和显示大文件(>1G),分享下一些摸索经验. 下文源码: compilelife/loginsight​github.com 文件的内存映射 在开始qt部分 ...

最新文章

  1. 一个利用正则表达式进行代码重构,去除冗余代码的例子
  2. 扩展中国剩余定理 exCRT 学习笔记
  3. shell foreach 拼接字符串_FIND_IN_SET 及IN 处理逗号间隔的字符串参数
  4. EventBus的基本使用步骤
  5. ==、Equals 、ReferenceEquals它们的异同
  6. 项目总结13:Jav文件压缩-InputStream转化为base64-Base64解码并生成图片
  7. 逻辑真题- 19/20年逻辑真题名师讲评 主讲人:王诚
  8. 结对编程_我从结对编程面试中学到的东西
  9. STK9 Object Browser灰色无法操作
  10. 银行核心系统之假期表
  11. python not in函数用法,pandas is in和not in的使用说明
  12. 教师薪金matlab,数学建模教师薪金问题.doc
  13. Socket+MFC的聊天室
  14. java实现单一登录 踢人效果
  15. 全球顶尖人工智能专家陶大程加入京东,出任京东探索研究院院长
  16. “地表最贵iPhone”到货,iPhone XS 系列手机等你来测!
  17. 手机前缀带字幕滚动筛选
  18. MATLAB在线编辑网站及使用教程
  19. ultraiso安装matlab,ubuntu U盘安装教程:UltraISO采用U盘安装ubuntu12.10
  20. 一篇评价牛顿的搞笑文章,作者老罗,但很有才

热门文章

  1. OpenWrt 安装中文语言包
  2. 哥德巴赫猜想(C++证明)
  3. 中国最美的100首情诗
  4. C# 实现自动ADSL拨号
  5. 八款android日历 [Calendar] 开源项目框架分类总汇
  6. 一阶微分方程组c语言编程,一阶常微分方程数值解的C语言编程实现
  7. 0910期即将上市:优秀产品三部曲
  8. 【业务安全05】业务逻辑漏洞之篡改交易数据——基于大米CMS-V5.4电子商城
  9. Python基础综合
  10. 看不见世界的程序员,开发了一款“吃鸡”