自定义控件 TextView 歌词 Lrc
演示
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
自定义View
/*** 歌词播放的自定义控件*/public class LrcView extends TextView {private String filePath = "/a.lrc";//文件路径private List<Lyrc> lyrcList;//歌词内容private int current = 0;//当前行private int lineSpacing = 70; //行间距//当前正在播放的行private Paint currentPaint;private int currentColor = Color.BLUE;//颜色private int currentSize = 55;//字体大小private Typeface currentTypeface = Typeface.DEFAULT_BOLD;//字体,默认的字体+粗体//其他行private Paint ortherPaint;private int ortherColor = Color.GREEN;private int ortherSize = 45;private Typeface ortherTypeface = Typeface.SERIF;//一种字体类型private Handler handler = new Handler() {public void handleMessage(Message msg) {invalidate();}};public LrcView(Context context) {this(context, null);}public LrcView(Context context, AttributeSet attrs) {super(context, attrs);lyrcList = LyrcUtil.readLRC(new File(Environment.getExternalStorageDirectory().getPath() + filePath));currentPaint = new Paint();currentPaint.setColor(currentColor);currentPaint.setTextSize(currentSize);currentPaint.setTextAlign(Align.CENTER);currentPaint.setTypeface(currentTypeface);ortherPaint = new Paint();ortherPaint.setColor(ortherColor);ortherPaint.setTextSize(ortherSize);ortherPaint.setTextAlign(Align.CENTER);ortherPaint.setTypeface(ortherTypeface);}public void setLrcType(String filePath, int lineSpacing, int currentColor, int currentSize, int ortherColor, int ortherSize) {lyrcList = LyrcUtil.readLRC(new File(filePath));this.lineSpacing = lineSpacing;currentPaint.setColor(currentColor);currentPaint.setTextSize(currentSize);ortherPaint.setColor(ortherColor);ortherPaint.setTextSize(ortherSize);}@Overrideprotected void onDraw(Canvas canvas) {if (current < lyrcList.size()) {if (lyrcList != null && lyrcList.size() > 0) {Lyrc lyrc = null;//画前面的内容for (int i = current - 1; i >= 0; i--) {lyrc = lyrcList.get(i);canvas.drawText(lyrc.lrcString, getWidth() / 2, getHeight() / 2 + lineSpacing * (i - current), ortherPaint);}//画当前的内容lyrc = lyrcList.get(current);canvas.drawText(lyrc.lrcString, getWidth() / 2, getHeight() / 2, currentPaint);//画后面的内容for (int i = current + 1; i < lyrcList.size(); i++) {lyrc = lyrcList.get(i);canvas.drawText(lyrc.lrcString, getWidth() / 2, getHeight() / 2 + lineSpacing * (i - current), ortherPaint);}//告诉handler当前行的时间lyrc = lyrcList.get(current);handler.sendEmptyMessageDelayed(10, lyrc.sleepTime);//当前行+1current++;} else canvas.drawText("未找到歌词", getWidth() / 2, getHeight() / 2, currentPaint);}super.onDraw(canvas);}}
工具类
public class LyrcUtil {private static List<Lyrc> lyrcList;/*** 读取文件*/public static List<Lyrc> readLRC(File f) {try {if (f == null || !f.exists()) {lyrcList = null;} else {lyrcList = new Vector<Lyrc>();InputStream is = new BufferedInputStream(new FileInputStream(f));BufferedReader br = new BufferedReader(new InputStreamReader(is, getCharset(f)));String strTemp = "";while ((strTemp = br.readLine()) != null) {strTemp = analyzeLRC(strTemp);}br.close();is.close();// 对歌词进行排序Collections.sort(lyrcList, new Sort());// 计算每行歌词的停留时间for (int i = 0; i < lyrcList.size(); i++) {Lyrc one = lyrcList.get(i);if (i + 1 < lyrcList.size()) {Lyrc two = lyrcList.get(i + 1);one.sleepTime = two.timePoint - one.timePoint;}}}} catch (Exception e) {e.printStackTrace();}return lyrcList;}/*** 处理一行内容*/private static String analyzeLRC(String text) {try {int pos1 = text.indexOf("[");int pos2 = text.indexOf("]");if (pos1 >= 0 && pos2 != -1) {Long time[] = new Long[getPossiblyTagCount(text)];time[0] = timeToLong(text.substring(pos1 + 1, pos2));if (time[0] == -1) return "";String strLineRemaining = text;int i = 1;while (pos1 >= 0 && pos2 != -1) {strLineRemaining = strLineRemaining.substring(pos2 + 1);pos1 = strLineRemaining.indexOf("[");pos2 = strLineRemaining.indexOf("]");if (pos2 != -1) {time[i] = timeToLong(strLineRemaining.substring(pos1 + 1, pos2));if (time[i] == -1) return ""; // LRCTexti++;}}Lyrc tl = null;for (int j = 0; j < time.length; j++) {if (time[j] != null) {tl = new Lyrc();tl.timePoint = time[j].intValue();tl.lrcString = strLineRemaining;lyrcList.add(tl);}}return strLineRemaining;} else return "";} catch (Exception e) {return "";}}private static int getPossiblyTagCount(String Line) {String strCount1[] = Line.split("\\[");String strCount2[] = Line.split("\\]");if (strCount1.length == 0 && strCount2.length == 0) return 1;else if (strCount1.length > strCount2.length) return strCount1.length;else return strCount2.length;}/*** 时间转换*/public static long timeToLong(String Time) {try {String[] s1 = Time.split(":");int min = Integer.parseInt(s1[0]);String[] s2 = s1[1].split("\\.");int sec = Integer.parseInt(s2[0]);int mill = 0;if (s2.length > 1) mill = Integer.parseInt(s2[1]);return min * 60 * 1000 + sec * 1000 + mill * 10;} catch (Exception e) {return -1;}}/*** 判断文件编码*/public static String getCharset(File file) {String charset = "GBK";byte[] first3Bytes = new byte[3];try {boolean checked = false;BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));bis.mark(0);int read = bis.read(first3Bytes, 0, 3);if (read == -1) return charset;if (first3Bytes[0] == (byte) 0xFF && first3Bytes[1] == (byte) 0xFE) {charset = "UTF-16LE";checked = true;} else if (first3Bytes[0] == (byte) 0xFE && first3Bytes[1] == (byte) 0xFF) {charset = "UTF-16BE";checked = true;} else if (first3Bytes[0] == (byte) 0xEF && first3Bytes[1] == (byte) 0xBB && first3Bytes[2] == (byte) 0xBF) {charset = "UTF-8";checked = true;}bis.reset();if (!checked) {int loc = 0;while ((read = bis.read()) != -1) {loc++;if (read >= 0xF0) break;if (0x80 <= read && read <= 0xBF) break;if (0xC0 <= read && read <= 0xDF) {read = bis.read();if (0x80 <= read && read <= 0xBF) continue;else break;} else if (0xE0 <= read && read <= 0xEF) {read = bis.read();if (0x80 <= read && read <= 0xBF) {read = bis.read();if (0x80 <= read && read <= 0xBF) {charset = "UTF-8";break;} else break;} else break;}}}bis.close();} catch (Exception e) {e.printStackTrace();}return charset;}private static class Sort implements Comparator<Lyrc> {public Sort() {}public int compare(Lyrc tl1, Lyrc tl2) {return sortUp(tl1, tl2);}private int sortUp(Lyrc tl1, Lyrc tl2) {if (tl1.timePoint < tl2.timePoint) return -1;else if (tl1.timePoint > tl2.timePoint) return 1;else return 0;}}}
bean
public class Lyrc {public String lrcString;public int sleepTime;public int timePoint;}
a.lrc
[00:00] 护花使者
[00:03] 李克勤
[00:38][00:05] 这晚在街中偶遇心中的她
[00:41][00:09] 两脚决定不听叫唤跟她归家
[00:44][00:12] 深宵的冷风 不准吹去她
[00:47][00:15] 她那幽幽眼神快要对我说话
[00:50][00:18] 纤纤身影飘飘身影默默转来吧
[00:54][00:21] 对我说浪漫情人爱我吗
[00:57][00:24] 贪心的晚风 竟敢拥吻她
[01:00][00:27] 将她秀发温温柔柔每缕每缕放下
[01:03][00:30] 卑污的晚风 不应抚慰她
[01:06][00:33] 我已决意一生护着心中的她
使用
public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);LrcView lrcView = new LrcView(this);lrcView.setLrcType(Environment.getExternalStorageDirectory().getPath() +"/a.lrc", dp2px(25), 0xffff00ff, dp2px(20), 0xff0000ff, dp2px(16));setContentView(lrcView);}/*** 根据手机的分辨率从 dp 的单位 转成为 px(像素)*/public int dp2px(float dpValue) {float scale = getResources().getDisplayMetrics().density;return (int) (dpValue * scale + 0.5f);}}
自定义控件 TextView 歌词 Lrc的更多相关文章
- IOS 解析歌词lrc
最近在捣鼓音乐播放器,过程中学到了一些东西,写下来分享一下,首先是歌词的解析 首先我们看看lrc(不贴维基了怕打不开 歌词文件一般是这样的格式 1.[分钟:秒.毫秒] 歌词 2. [分钟:秒] 歌词 ...
- 自定义控件TextView
public class defineTextView extends TextView { Context context; public defineTextView(Context contex ...
- Android 自定义控件-TextView
很多时候系统自带的View满足不了设计的要求,就需要自定义View控件.自定义View首先要实现一个继承自View的类.添加类的构造方法,override父类的方法,如onDraw,(onMeasur ...
- LRC歌词原理和实现高仿Android网易云音乐
大家好,我们是爱学啊,今天给大家带来一篇关于LRC歌词原理和在Android上如何实现歌词逐行滚动的效果,本文来自[Android开发项目实战我的云音乐]课程:逐字滚动下一篇文章讲解. 效果图 相信大 ...
- 网页音乐播放器javascript实现,可以显示歌词
可以显示歌词,但是歌词和歌曲都要实现自己下载下来.只能播放一首歌,歌词还得是lrc格式的代码写的很罗嗦,急切希望帮改改CSS的代码1.代码:<html > <head> ...
- Ubuntu下实现歌词解析
我们要明确目的,实现歌曲歌词同步. 1.将歌词文件一次性去取到内存中.(以周董的“简单爱”为例) a.用fopen打开歌词文件 FILE *fp = fopen(“简单爱.lrc”,"r& ...
- Android Toolbar 开发总结
初识 Toolbar Toolbar是在 Android 5.0 开始推出的一个 Material Design 风格的导航控件 ,Google 非常推荐大家使用 Toolbar 来作为Android ...
- Android M 控件:Snackbar、Toolbar、TabLayout、NavigationView
Snackbar Snackbar提供了一个介于Toast和AlertDialog之间轻量级控件,它可以很方便的提供消息的提示和动作反馈.Snackbar的使用与Toast的使用基本相同: Snack ...
- [MFC] MFC音乐播放器 傻瓜级教程 网络 搜索歌曲 下载
>目录< >——————————————————————< 1.建立工程 1.建立一个MFC工程,命名为Tao_Music 2.选择为基本对话框 3.包含Windows So ...
随机推荐
- javaScript高程第三版读书笔记
看完<dom编程艺术>现在准备读进阶版的js高程了,由于篇幅较长,所以利用刚看完<dom编程艺术>学到的知识写了段JavaScript代码,来折叠各章的内容.并且应用到了< ...
- js获取本月、三个月、今年的日期插件dateHelp
最近看了一些关于面向对象的知识,最近工作中在做统计查询的时候需要用到本月.近三个月.今年的日期范围,所以下面用用面向对象的思想写了一个获取日期的插件,大家可以借鉴使用. 直接通过new DateHel ...
- oracle删除互相关联的记录
今天遇到一个问题,在数据库中删除一条记录,但是在删除的时候报错了,报出该记录已经被其他子记录引用,想了好久不知道怎么做,后来发现报错提示信息中会提示删除该记录时影响了那个约束条件,于是思路出来了: 1 ...
- Delphi笔记(GL_Scene安装及简单使用)
前一段时间,需要弄一个四轴的监控平台,看了匿名的上位机后,十分感兴趣.于是我也想自己也弄一个上位机来玩玩,在将串口通讯调好了以后,就开始好奇那个3D模型是怎么弄的.在网上面查找了很多资料,由于我用的是 ...
- C语言 位操作
c语言位操作中需要注意有: 位操作只针对整型和字符型数据 在右移操作中:对无符号数和有符号中的正数补 0:符号数中的负数,取决于所使用的系统:补 0 的称为“逻辑右移”,补 1 的称为“算术右移”. ...
- SpringMVC入门2-注解开发
Spring MVC 注解开发 <context:component-scan base-package="com.controls" /> Springmvc的扫描器 ...
- MappedByteBuffer高速缓存文件、RandomAccessFile随机访问
说到高速缓存存储,处理读写文件,那就不得不说MappedByteBuffer. 看了好多文章以后写一下自己的总结. 在这里先介绍一下相关的类与方法. 先说一下Buffer.ByteBuffer.Map ...
- MyEclipse10 中增加svn插件
http://www.cnblogs.com/bluesky4485/archive/2012/04/23/2467177.html 确实这种方法可行!向牛人学习!
- pl/sql 程序块里打印问题
declare v_number NUMBER; v_number2 NUMBER; begin select count(*) into v_number from dual; DBMS_OUTPU ...
- Android子线程更新主界面
学习什么的还是要真正的有应用,有需求才能在最短的时间里面牢牢掌握一项技术. 今天就是这样的,产品一个需求下来,十万火急啊.然后之前只稍稍接触过,只能硬着头皮上了.最后牢牢地掌握了最简单的Handler ...
