android程式設計例項-音樂播放器之歌詞顯示
阿新 • • 發佈:2019-01-07
今天分享一個歌詞顯示的專案,首先讓我們來看看一般歌詞是什麼樣的格式,就拿神曲《小蘋果》來說的,請看歌詞:
[00:00.91]小蘋果 [00:01.75]作詞:王太利 作曲:王太利 [00:02.47]演唱:筷子兄弟 [00:03.32] [00:17.40]我種下一顆種子 [00:19.12]終於長出了果實 [00:21.04]今天是個偉大日子 [00:25.10]摘下星星送給你 [00:26.79]拽下月亮送給你 [00:28.77]讓太陽每天為你升起 [00:31.25] [00:32.67]變成蠟燭燃燒自己 [00:34.47]只為照亮你 [00:36.44]把我一切都獻給你 [00:38.22]只要你歡喜 [00:40.19]你讓我每個明天都 [00:42.15]變得有意義 [00:44.04]生命雖短愛你永遠 [00:46.08]不離不棄 [00:47.81] [00:48.15]你是我的小呀小蘋果兒 [00:51.92]怎麼愛你都不嫌多 [00:55.26]紅紅的小臉兒溫暖我的心窩 [00:59.33]點亮我生命的火 火火火火 [01:03.45]你是我的小呀小蘋果兒 [01:07.06]就像天邊最美的雲朵 [01:10.61]春天又來到了花開滿山坡 [01:14.70]種下希望就會收穫
新建一個java類Lyrc來表示歌詞
public class Lyrc {
public String lrcString; //歌詞
public int sleepTime; //一行歌詞的持續時間
public int timePoint; //一行歌詞結束的時間點
}
新建java類對歌詞進行處理,歌詞中一行裡有時間[00:48.15],用[ ]括起來,緊接著是歌詞內容,我們一行一行的將歌詞讀入,並將時間和歌詞分離。
public class LyrcUtil { private static List<Lyrc> lyrcList; /** * 讀取歌詞檔案檔案 * @param f * @return */ 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; } /** * 處理歌詞中的一行內容 * * @param text * @return */ 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; } /** * 時間轉換 * * @param Time * @return */ 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; } } /** * 判斷檔案的編碼型別 * * @param file * @return */ 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; } } }
新建顯示歌詞的類LrcView
<pre name="code" class="java">public class LrcView extends TextView { private List<Lyrc> lyrcList; private int current = 0; // 行的間距 private int lineSpacing = 30; // 當前正在繪製的行 private Paint currentPaint; private int currentColor = Color.GREEN; private int currentSize = 18; private Typeface currentTypeface = Typeface.DEFAULT_BOLD; private Paint ortherPaint; private int ortherColor = Color.BLACK; private int ortherSize = 15; private Typeface ortherTypeface = Typeface.SERIF; private Handler handler = new Handler() { public void handleMessage(Message msg) { invalidate(); //重複onDraw()方法 } }; public LrcView(Context context, AttributeSet attrs) { super(context, attrs); lyrcList = LyrcUtil.readLRC(new File("/sdcard/小蘋果.lrc")); 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); } @Override protected void onDraw(Canvas canvas) { // getWidth(); // getHeight(); 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); } lyrc=lyrcList.get(current); handler.sendEmptyMessageDelayed(10, lyrc.sleepTime); current++; } else { canvas.drawText("未找到歌詞", getWidth() / 2, getHeight() / 2, currentPaint); } } super.onDraw(canvas); } }
在res/layout下建立一個activity_main.xml,將LrcView 包含進來
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<com.zhuzhu.LrcView
android:id="@+id/lrcview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
在Activity中進行顯示
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}