手机影音项目笔记(四)---音乐播放歌词的控件的自定义
来源:互联网 发布:微信公众java开发 编辑:程序博客网 时间:2024/04/27 23:27
LyricsView
public class LyricsView extends TextView { private Paint mPaint; private int HIGHLIGHTT_COLOR; private int NORMAL_COLOR; private int HIGHLIGHT_SIZE; private int NORMMAL_SIZE; private int mViewW; private int mViewH; private ArrayList<Lyric> lyricArrayList; private int centerIndex; private int LINE_HEIGHT; private int mDuration; private int mPosition; public LyricsView(Context context) { super(context); initView(); } public LyricsView(Context context, AttributeSet attrs) { super(context, attrs); initView(); } public LyricsView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(); } private void initView() { HIGHLIGHT_SIZE = getResources().getDimensionPixelSize(R.dimen.hightlight_size); NORMMAL_SIZE = getResources().getDimensionPixelSize(R.dimen.normal_size); LINE_HEIGHT = getResources().getDimensionPixelSize(R.dimen.line_height); HIGHLIGHTT_COLOR = Color.GREEN; NORMAL_COLOR = Color.WHITE; mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setColor(HIGHLIGHTT_COLOR); mPaint.setTextSize(HIGHLIGHT_SIZE); // 伪造歌词数据// lyricArrayList = new ArrayList<>();// for (int i = 0; i < 30; i++) {// lyricArrayList.add(new Lyric(i * 2000,"当前歌词的行数为:"+i));// }// centerIndex = 16; } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mViewW = w; mViewH = h; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (lyricArrayList == null || lyricArrayList.size() == 0) { drawSingleLineText(canvas); } else { drawMuliteLineText(canvas); } } private void drawMuliteLineText(Canvas canvas) { // 获取据中行的歌词 Lyric lyric = lyricArrayList.get(centerIndex);// 移动的距离 = 已消耗时间百分比 * 行高// 已消耗时间百分比 = 已消耗时间 / 可用时间// 已消耗时间 = 当前播放进度 - 行起始时间// 可用时间 = 下一行起始时间 - 行起始时间 // 下一行起始时间 int nextStartPoint ; if (centerIndex != lyricArrayList.size()-1){ // 非最后一行 Lyric nextLyric = lyricArrayList.get(centerIndex + 1); nextStartPoint = nextLyric.getStartPoint(); }else{ // 最后一行 nextStartPoint = mDuration; } // 可用时间 int lineTime = nextStartPoint - lyric.getStartPoint(); // 已消耗时间 int pastTime = mPosition - lyric.getStartPoint(); // 已消耗时间百分比 float pastPercent = pastTime / (float)lineTime; // 移动的距离 float offsetY = pastPercent * LINE_HEIGHT; // 计算居中行的Y位置 // 获取文本宽高 Rect bounds = new Rect(); mPaint.getTextBounds(lyric.getContent(),0,lyric.getContent().length(),bounds); // 计算居中行的Y坐标 float centerY = mViewH / 2 + bounds.height() / 2 - offsetY; for (int i = 0; i < lyricArrayList.size(); i++) { if (i!=centerIndex){ // 不是居中行 mPaint.setColor(NORMAL_COLOR); mPaint.setTextSize(NORMMAL_SIZE); }else{ // 居中行 mPaint.setColor(HIGHLIGHTT_COLOR); mPaint.setTextSize(HIGHLIGHT_SIZE); } Lyric drawLyric = lyricArrayList.get(i); // centerY + lineH * (drawIndex - centerIndex) float drawY = centerY + LINE_HEIGHT * (i - centerIndex); drawHorizontalText(canvas, drawLyric.getContent(), drawY); } } private void drawHorizontalText(Canvas canvas, String text, float drawY) { // 获取文本宽高 Rect bounds = new Rect(); mPaint.getTextBounds(text,0,text.length(),bounds); // 计算绘制文本的坐标 float drawX = mViewW / 2 - bounds.width() / 2; canvas.drawText(text, drawX, drawY, mPaint); } private void drawSingleLineText(Canvas canvas) { String text = "正在加载歌词...";// X = view宽度的一半 - 文本宽度的一半// Y = view高度的一半 + 文本高度的一半 // 获取文本宽高 Rect bounds = new Rect(); mPaint.getTextBounds(text,0,text.length(),bounds); // 计算绘制文本的坐标 float drawX = mViewW / 2 - bounds.width() / 2; float drawY = mViewH / 2 + bounds.height() / 2; canvas.drawText(text, drawX, drawY, mPaint); } // 根据当前歌曲的播放进度,更新居中行的位置 public void computeCenterIndex(int position,int duration){ mPosition = position; mDuration = duration; // 比较所有行的起始时间,如果比较行的时间比播放时间小,并且下一行的时间比播放时间大 for (int i = 0; i < lyricArrayList.size(); i++) { Lyric lyric = lyricArrayList.get(i); int nextStartPoint; if (i!=lyricArrayList.size()-1){ // 不是最后一行歌词 Lyric nextLyric = lyricArrayList.get(i + 1); nextStartPoint = nextLyric.getStartPoint(); }else{ nextStartPoint = duration; } if (lyric.getStartPoint() <= position && nextStartPoint > position){ centerIndex = i; break; } } invalidate(); } // 更新歌词文件 public void setLyricsFile(File lyricsFile){ lyricArrayList = LyricsParser.parserFromFile(lyricsFile); centerIndex = 0; }}LyricsLoader
public class LyricsLoader { private static final File ROOT = new File(Environment.getExternalStorageDirectory(),"Download/audio"); // 根据指定的歌曲名,加载到对应的歌词文件 public static File loadFile(String title){ File file = new File(ROOT,title+".lrc"); if (file.exists()){ return file; } file = new File(ROOT, title+".txt"); if (file.exists()){ return file; } // 到专门存放歌词的文件夹查找 //... // 连接服务器下载歌词文件 // ... return null; }}LyricsParser
public class LyricsParser { // 从文件解析出歌词数据列表 public static ArrayList<Lyric> parserFromFile(File lyricsFile){ ArrayList<Lyric> lyrics = new ArrayList<>(); // 数据可用性验证 if (lyricsFile == null || !lyricsFile.exists()) { lyrics.add(new Lyric(0, "无法解析歌词文件")); return lyrics; } // 按行读取歌词并解析 try { BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(lyricsFile),"GBK")); String line ; while ((line= br.readLine())!=null){ // [01:22.04][02:35.04]寂寞的夜和谁说话 ArrayList<Lyric> lineLyrics = parserLine(line); lyrics.addAll(lineLyrics); } } catch (Exception e) { e.printStackTrace(); } Collections.sort(lyrics); return lyrics; } // 解析一行歌词 [01:22.04][02:35.04]寂寞的夜和谁说话 private static ArrayList<Lyric> parserLine(String line) { ArrayList<Lyric> lineLyrics = new ArrayList<>(); String[] splitArr = line.split("]"); // [01:22.04 [02:35.04 寂寞的夜和谁说话 String content = splitArr[splitArr.length-1]; // [01:22.04 [02:35.04 for (int i = 0; i < splitArr.length - 1; i++) { int startPoint = parserStartPoint(splitArr[i]); lineLyrics.add(new Lyric(startPoint,content)); } return lineLyrics; } // 解析歌词起始时间 [02:35.04 private static int parserStartPoint(String time) { String[] splitArr = time.split(":"); // [02 35.04 String minStr = splitArr[0].substring(1); // 35.04 String[] split = splitArr[1].split("\\."); // 35 04 String secStr = split[0]; String msecStr = split[1]; // 将字符串转换为数值 int min = Integer.parseInt(minStr); int sec = Integer.parseInt(secStr); int msec = Integer.parseInt(msecStr); // 合成时间戳 int startPoint = min * 60 * 1000 + sec * 1000 + msec * 10; return startPoint; }}Lyric
public class Lyric implements Comparable<Lyric>{ private int startPoint; private String content; public Lyric(int startPoint, String content) { this.startPoint = startPoint; this.content = content; } public int getStartPoint() { return startPoint; } public void setStartPoint(int startPoint) { this.startPoint = startPoint; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } @Override public String toString() { return "Lyric{" + "startPoint=" + startPoint + ", content='" + content + '\'' + '}'; } @Override public int compareTo(Lyric another) { return startPoint - another.startPoint; }}
0 0
- 手机影音项目笔记(四)---音乐播放歌词的控件的自定义
- 手机影音项目笔记(三)---音乐播放的处理
- 音乐播放器自定义控件歌词解析
- android MusicPlayer 音乐播放器 Lrc歌词控件的实现
- 原生JS的网页手机音乐播放器 歌词同步播放
- 手机影音项目笔记(二)-----视频播放处理
- 手机影音项目笔记(一)
- 音乐播放器的滚动歌词的实现
- 关于音乐播放器中歌词同步显示的实现
- 本地MediaPlayer音乐播放器与歌词同步的实现
- android 音乐播放的歌词 编码判断及提取
- 音乐播放器歌词的逐字渲染效果
- android 音乐播放器关于歌词的处理
- LyricView是一个强大而灵活的自定义视图,可以在Android的音乐播放器中显示歌词
- 酷狗音乐展示滚动歌词效果的控件实现
- android手机音乐播放器实现歌词同步
- 苹果手机上音乐播放的问题
- 歌词播放的原理
- hdu 1584 蜘蛛牌
- 自定义结构体通过模板实现
- Python如何读写文本文件
- ibatis中sql的报错信息解析
- Handler, Thread, Looper, Message,一图胜千言
- 手机影音项目笔记(四)---音乐播放歌词的控件的自定义
- 4 :jvm 垃圾回收机制
- FileOutputStream应用中'java.io.FileNotFoundException:'
- 7 :Tomcat中JVM内存溢出及合理配置
- C#委托和事件
- Leetcode-155. Min Stack
- LintCode 单词搜索 II
- zTree初涉
- zookeeper系列之异步通知模式-Watcher