作者:雨过后放晴 | 来源:互联网 | 2023-10-10 11:09
实现歌词同步介绍:利用TextView实现歌词同步显示,这是一个简单的利用TextView实现滚动实时显示歌词的。里面的内容都已经写上了详细的注释。里面播放音乐的时候歌词同
实现歌词同步
介绍:
利用TextView实现歌词同步显示,这是一个简单的利用TextView实现滚动实时显示歌词的。
里面的内容都已经写上了详细的注释。里面播放音乐的时候歌词同步展示。
做媒体这块的朋友可以学习一下,练练歌词同步实现方法。
歌词实现展示类TextShow,
项目源码来源:http://www.itlanbao.com/code/20151214/10000/100695.html
效果截图:
?
主要代码如下:
package com.example.textviewchange;
import java.io.BufferedReader;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import android.app.Activity;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.widget.TextView;
public class MainActivity extends Activity {
private MediaPlayer player;
private TextView tv;
private boolean flag=false;//用来停止和判断线程
private int i;
private TextShow ts;
private Map map,map1;
private int count=5;
private List list;
private String s="";
private boolean change=false;
Looper looper=Looper.getMainLooper();
Handler handler=new Handler(looper){
public void handleMessage(android.os.Message msg) {
if(msg.what==10&&flag==false){
if(i==map1.size()){//判断歌词是不是已经全部显示
flag=true;
//如果销毁了activity则,不执行下面的方法
return;
}
Changetext();
}
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv=(TextView)findViewById(R.id.tv);
//获取assert中的歌曲文件以及歌词文件
AssetManager am=getAssets();
AssetFileDescriptor afd;
//使用媒体播放器
player=new MediaPlayer();
//设置播放的音频类型
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
afd = am.openFd("apple.mp3");
FileDescriptor fd=afd.getFileDescriptor();
player.setDataSource(fd);
//获取sd卡中的歌曲文件
//player.setDataSource("/sdcard/Music/apple.mp3");
player.prepare();
} catch (IOException e1) {
e1.printStackTrace();
}
//开始播放
player.start();
//测试,这里应该用输入输出流读取文件
map1=new HashMap<>();
list=new ArrayList<>();
//加载歌词文件
read();
//保留插入顺序
//设置给显示界面刚开始显示5行
map=new LinkedHashMap();
for(int i=0;i<5;i++){
map.put(list.get(i), map1.get(list.get(i)));
}
ts=new TextShow(map);
new Thread(){
public void run() {
while(!flag){
try {
sleep(500);
Message mes=new Message();
mes.what=10;
handler.sendMessage(mes);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}.start();
}
public void Changetext(){
//给正在播放的歌词添加样式
if(map!=null&&map.get(conTime(player.getCurrentPosition()))!=null){
String s1="";
tv.setText(ts.Add(conTime(player.getCurrentPosition()).toString()));
s1=conTime(player.getCurrentPosition()).toString();
//判断在相同的时间段内,Changetext方法是不是执行了两次
if(!s.equals(s1)){
change=true;
s=s1;
}else{
change=false;
}
if(change){
//设置正在播放的歌词的上方的行数
if(i>5){
//移除最顶部的一行
map.remove(list.get(i-6));
}
//增加一行在最底部
if(count map.put(list.get(count), map1.get(list.get(count)));
}
i++;
count++;
}
}
}
//读取LRC的歌词文件
public void read(){
try {
InputStream in=getAssets().open("c.lrc");
BufferedReader bf=new BufferedReader(new InputStreamReader(in));
String msg="";
while((msg=bf.readLine())!=null){
if(msg.length()!=0){
//保存歌词的时间以及歌词内容
map1.put(msg.substring(1,6), msg.substring(msg.lastIndexOf("]")+1)+"\n");
//保存每一行歌词的时间
list.add(msg.substring(1,6));
}
}
bf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if(player!=null){
player.stop();
player.release();
player=null;
}
flag=true;
}
//将音频的播放时间转换成00:00的格式
public CharSequence conTime(int duration) {
int secOnd=duration/1000;
int miunte=second/60;
secOnd=second%60;
String miunte1 = String.valueOf(miunte);
String second1 = String.valueOf(second);
if(miunte<10){
miunte1="0"+miunte;
}if(second<10){
second1="0"+second;
}
return miunte1+":"+second1;
}
}?
?特殊文字显示 (歌词同步显示)
package com.example.textviewchange;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import android.graphics.Color;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.style.AbsoluteSizeSpan;
import android.text.style.ForegroundColorSpan;
/*
* 特殊文字显示 (歌词同步显示)
* */
public class TextShow {
private SpannableStringBuilder ssb;
private SpannableString ss;
//private String str;
private Map map;
//传入的map必须为LinkedHashMap
public TextShow(Map map) {
this.map=map;
ssb=new SpannableStringBuilder();
}
//设置字符串的样式(如果要分行显示,在传入的字符串中添加"\n")
//根据字符串从map中取值
public SpannableString changeText(String str){
ss=new SpannableString(str);
//设置字符串的大小
ss.setSpan(new AbsoluteSizeSpan(50),0,ss.length(),Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
//设置字符串的颜色
ss.setSpan(new ForegroundColorSpan(Color.MAGENTA), 0, ss.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
return ss;
}
//追加到SpannableStringBuilder中某一行
//ss 需要追加的有样式的字符串
public SpannableStringBuilder Add(String str){
//清除上一次的数据
ssb.clear();
//遍历map
Iterator> iter = map.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
String key = entry.getKey();
String val = entry.getValue();
if(key.equals(str)){
ssb.append(changeText(val));
}
else{
SpannableString ss1=new SpannableString(val);
ssb.append(ss1);
}
}
/* 也可以用下面的方法
* for(String string:map.values()){
if(string.equals(map.get(str))){
ssb.append(changeText(str));
}else{
SpannableString ss1=new SpannableString(string);
ssb.append(ss1);
}
}*/
return ssb;
}
}?