演示
<uses-permission android:name="android.permission.INTERNET" /> <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); } @Override protected 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); //当前行+1 current++; } 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 ""; // LRCText i++; } } 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; } } }
使用
public class MainActivity extends Activity { @Override protected 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); } }
时间: 2024-10-18 17:21:16