实现歌词同步源码

标签: 歌词 同步 源码 | 发表时间:2015-12-14 15:05 | 作者:
出处:http://www.iteye.com

实现歌词同步

介绍:

利用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<String,String> map,map1;
	private int count=5;
	private List<String> 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<String,String>();
				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<map1.size()){
			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<String,String> map;
	//传入的map必须为LinkedHashMap
	public TextShow(Map<String,String> 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<Entry<String, String>> iter = map.entrySet().iterator();
		while (iter.hasNext()) {
			Map.Entry<String,String> entry = (Map.Entry<String,String>) 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;
	}
}

 



已有 0 人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



相关 [歌词 同步 源码] 推荐:

实现歌词同步源码

- - ITeye博客
利用TextView实现歌词同步显示,这是一个简单的利用TextView实现滚动实时显示歌词的. 里面的内容都已经写上了详细的注释. 里面播放音乐的时候歌词同步展示. 做媒体这块的朋友可以学习一下,练练歌词同步实现方法. 歌词实现展示类TextShow,. 项目源码来源: http://www.itlanbao.com/code/20151214/10000/100695.html.

谷奥: 让 Google Music 同步显示歌词的脚本 Google Music Lyrics

- brahms - 谷奥聚合——谷奥主站+谷安 aggregator
Google Music Lyrics是一个为Firefox设计的Greasemonkey油猴脚本,可以让你在Google Music的侧边栏里显示播放着的音乐的歌词. 歌词全部来自SongLyrics.com,而且可以缓存在本地,所以你下次再播放同一首歌的时候会立刻显示出来而不必联网再找. 你甚至可以编辑歌词并利用HTML 5的本地化存储功能保存下来.

linux时间同步

- - BlogJava-首页技术区
第一步的意思是设置时间,设置完了可以用date命令查看对不对...注意是月日时分年  . 第二步的意思是写入主板的rtc芯片..  . su -c 'date -s 月/日/年'  . su -c 'date -s 时:分:秒'  . 由于Linux时钟和Windows时钟从概念的分类、使用到设置都有很大的不同,所以,搞清楚Linux时钟的工作方式与设置操作,不仅对于Linux初学者有着重大意义,而且对于使用Linux服务器的用户来说尤为重要.

nginx + memcached session 同步

- - 企业架构 - ITeye博客
squid 缓存疑问 问题归纳:. 1 squid 缓存的数据,何时过期,如何判断缓存的数据已经过期,如何把最新的数据缓入squid 并且替换掉旧的内容. 2 如何判断数据是否应该被缓存. 3 校验失败时,是否给出缓存中旧的内容. 上面的几个问题  都可以通过 squid中的 refresh_pattern 配置项 找到答案.

用wget同步ftp

- - 天空极速
wget 可以下载整个网站或者ftp. 如果有两个ftp站点,需要同步,可以使用以下命令:. 解释下,前面是ftp的授权用户,密码,ftp的站点,端口. -r 是表示递归,-x表示强制创建目录,-c表示断点续传. Tags - windows , wget , ftp , 备份 , 同步.

Rsync同步使用

- - 开源软件 - ITeye博客
rsync是类unix系统下的数据镜像备份工具——remote sync. /etc/rsyncd/rsyncd.conf 是你刚才编辑的rsyncd.conf的位置. 也可以在/etc/rc.d/rc.local里加入让系统自动启动等. rsync -参数 用户名@同步服务器的IP::rsyncd.conf中那个方括号里的内容 本地存放路径 如:.

同步mysql数据到hive

- - ITeye博客
地址为:http://archive.cloudera.com/cdh/3/下载相应版本,如sqoop-1.2.0-CDH3B4.tar.gz. 地址为:http://archive.cloudera.com/cdh/3/,版本可以为hadoop-0.20.2-CDH3B4.tar.gz. 3.解压 sqoop-1.2.0-CDH3B4.tar.gz ,hadoop-0.20.2-CDH3B4.tar.gz 到某目录如/home/hadoop/,解压后的目录为.

Java同步块(Synchronized Blocks)

- - 并发编程网 - ifeve.com
原文链接  作者:Jakob Jenkov  译者:李同杰. Java 同步块(synchronized block)用来标记方法或者代码块是同步的. Java同步关键字(synchronzied). Java 同步关键字( synchronized ). Java中的同步块用synchronized标记.

bucardo5.3 postgres主从同步

- - x-marker的博客
在报表应用、olap等领域,bucardo可以把数据实时异步的传输到备库,然后在备库中可以进行数据转换、建临时表、报表等操作,而pg原生的stream replication只能是只读操作,所以bucardo的应用领域还是很广的. 今天分两篇分别记录下pg到pg的主从同步和pg到mysql的主从同步.

Java多线程(二)同步

- - CSDN博客编程语言推荐文章
如果你的java基础较弱,或者不大了解java多线程请先看这篇文章 java多线程(一)线程定义、状态和属性. 同步一直是java多线程的难点,在我们做android开发时也很少应用,但这并不是我们不熟悉同步的理由. 希望这篇文章能使更多的人能够了解并且应用java的同步. 在多线程的应用中,两个或者两个以上的线程需要共享对同一个数据的存取.