1. 程式人生 > >實現歌詞滾動

實現歌詞滾動

## LrcView 自定義控制元件 ##

package com.example.music.lrc;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.widget.TextView;

public class LrcView extends TextView {

private float width; // 歌詞檢視寬度
private float height; // 歌詞檢視高度
private Paint currentPaint; // 當前畫筆物件
private Paint notCurrentPaint; // 非當前畫筆物件
private float textHeight = 50; // 文字高度
private float textMaxSize = 24; //高亮文字大小
private float textSize = 20; // 文字大小
private int index = 0; // list集合下標
private LrcInfo infos; // 歌詞資訊

public void setmLrcList(LrcInfo infos) {
    this.infos = infos;
}

public LrcView(Context context) {
    super(context);
    init();
}

public LrcView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init();
}

public LrcView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init();
}

private void init() {

    setFocusable(true); // 設定可對焦
    // 顯示歌詞部分
    currentPaint = new Paint();
    currentPaint.setAntiAlias(true); // 設定抗鋸齒,讓文字美觀飽滿
    currentPaint.setTextAlign(Paint.Align.CENTER);// 設定文字對齊方式

    // 非高亮部分
    notCurrentPaint = new Paint();
    notCurrentPaint.setAntiAlias(true);
    notCurrentPaint.setTextAlign(Paint.Align.CENTER);
}

/**
 * 繪畫歌詞
 */
@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if (canvas == null) {
        return;
    }

    currentPaint.setColor(Color.argb(210, 251, 248, 29));
    notCurrentPaint.setColor(Color.argb(140, 255, 255, 255));

    currentPaint.setTextSize(textMaxSize);
    currentPaint.setTypeface(Typeface.SERIF);

    notCurrentPaint.setTextSize(textSize);
    notCurrentPaint.setTypeface(Typeface.DEFAULT);

    try {
        setText("");
        canvas.drawText(infos.getLrcLists().get(index).getContent(), width / 2, height / 2, currentPaint);
        float tempY = height / 2;
        // 畫出本句之前的句子
        for (int i = index - 1; i >= 0; i--) {
            // 向上推移
            tempY = tempY - textHeight;
            canvas.drawText(infos.getLrcLists().get(i).getContent(), width / 2, tempY, notCurrentPaint);
        }
        tempY = height / 2;
        // 畫出本句之後的句子
        for (int i = index + 1; i < infos.getLrcLists().size(); i++) {
            // 往下推移
            tempY = tempY + textHeight;
            canvas.drawText(infos.getLrcLists().get(i).getContent(), width / 2, tempY, notCurrentPaint);
        }
    } catch (Exception e) {
        setText("...缺少歌詞檔案...");
    }

}

/**
 * 當view大小改變的時候呼叫的方法
 */

protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    this.width = w;
    this.height = h;
}

public void setIndex(int index) {
    this.index = index;
}
}

LrcParse 類

package com.example.music.lrc;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.regex.Matcher;
import
java.util.regex.Pattern; public class LrcParse { private LrcInfo lrcInfo = new LrcInfo(); public static String charSet = "utf-8"; //編碼格式 //歌詞存放地地方 private String Path; //時間 private long currentTime; //對應時間的內容 private String currentContent; //儲存時間點和內容 ArrayList<LrcList> lrcLists = new
ArrayList<LrcList>(); private InputStream inputStream; public LrcParse(String path) { this.Path = path.replace(".mp3", ".lrc"); } public LrcInfo readLrc() { //定義一個StringBuilder物件,用來存放歌詞內容 StringBuilder stringBuilder = new StringBuilder(); try { inputStream = new FileInputStream(this.Path); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, charSet)); String str = null; //逐行解析 while ((str = reader.readLine()) != null) { if (!str.equals("")) { decodeLine(str); } } //全部解析完後,設定lrcLists lrcInfo.setLrcLists(lrcLists); return lrcInfo; } catch (FileNotFoundException e) { e.printStackTrace(); LrcList lrcList = new LrcList(); //設定時間點和內容的對映 lrcList.setContent("歌詞檔案沒發現!"); lrcLists.add(lrcList); lrcInfo.setLrcLists(lrcLists); return lrcInfo; } catch (IOException e) { e.printStackTrace(); LrcList lrcList = new LrcList(); //設定時間點和內容的對映 lrcList.setContent("沒有讀取到歌詞!"); lrcLists.add(lrcList); lrcInfo.setLrcLists(lrcLists); return lrcInfo; } } /** * 單行解析 */ private LrcInfo decodeLine(String str) { if (str.startsWith("[ti:")) { // 歌曲名 lrcInfo.setTitle(str.substring(4, str.lastIndexOf("]"))); // lrcTable.put("ti", str.substring(4, str.lastIndexOf("]"))); } else if (str.startsWith("[ar:")) {// 藝術家 lrcInfo.setArtist(str.substring(4, str.lastIndexOf("]"))); } else if (str.startsWith("[al:")) {// 專輯 lrcInfo.setAlbum(str.substring(4, str.lastIndexOf("]"))); } else if (str.startsWith("[by:")) {// 作詞 lrcInfo.setBySomeBody(str.substring(4, str.lastIndexOf("]"))); } else if (str.startsWith("[la:")) {// 語言 lrcInfo.setLanguage(str.substring(4, str.lastIndexOf("]"))); } else { //設定正則表示式,可能出現一些特殊的情況 String timeflag = "\\[(\\d{1,2}:\\d{1,2}\\.\\d{1,2})\\]|\\[(\\d{1,2}:\\d{1,2})\\]"; Pattern pattern = Pattern.compile(timeflag); Matcher matcher = pattern.matcher(str); //如果存在匹配項則執行如下操作 while (matcher.find()) { //得到匹配的內容 String msg = matcher.group(); //得到這個匹配項開始的索引 int start = matcher.start(); //得到這個匹配項結束的索引 int end = matcher.end(); //得到這個匹配項中的陣列 int groupCount = matcher.groupCount(); for (int index = 0; index < groupCount; index++) { String timeStr = matcher.group(index); if (index == 0) { //將第二組中的內容設定為當前的一個時間點 currentTime = str2Long(timeStr.substring(1, timeStr.length() - 1)); } } //得到時間點後的內容 String[] content = pattern.split(str); //將內容設定為當前內容,需要判斷只出現時間的情況,沒有內容的情況 if (content.length == 0) { currentContent = ""; } else { currentContent = content[content.length - 1]; } LrcList lrcList = new LrcList(); //設定時間點和內容的對映 lrcList.setCurrentTime(currentTime); lrcList.setContent(currentContent); lrcLists.add(lrcList); } } return this.lrcInfo; } private long str2Long(String timeStr) { //將時間格式為xx:xx.xx,返回的long要求以毫秒為單位 String[] s = timeStr.split("\\:"); int min = Integer.parseInt(s[0]); int sec = 0; int mill = 0; if (s[1].contains(".")) { String[] ss = s[1].split("\\."); sec = Integer.parseInt(ss[0]); mill = Integer.parseInt(ss[1]); } else { sec = Integer.parseInt(s[1]); } //時間的組成 return min * 60 * 1000 + sec * 1000 + mill * 10; } }
package com.example.music.lrc;

public class LrcList {
     //儲存當前時間
    private long currentTime;
    //儲存內容
    private String content;

    public long getCurrentTime() {
        return currentTime;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public void setCurrentTime(long currentTime) {
        this.currentTime = currentTime;
    }

    public String getContent() {
        return content;
    }
}
package com.example.music.lrc;

import java.util.ArrayList;

public class LrcInfo {

    private String title;//標題
    private String artist;//歌手
    private String album;//專輯名字
    private String bySomeBody;//歌詞製作者
    private String offset;
    private String language;   //語言
    private String errorinfo;   //錯誤資訊


    //儲存歌詞資訊和時間點
    ArrayList<LrcList> lrcLists;

    public String getLanguage() {
        return language;
    }

    public void setLanguage(String language) {
        this.language = language;
    }

    public void setErrorinfo(String errorinfo) {
        this.errorinfo = errorinfo;
    }

    public String getErrorinfo() {
        return errorinfo;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getArtist() {
        return artist;
    }

    public void setArtist(String artist) {
        this.artist = artist;
    }

    public String getAlbum() {
        return album;
    }

    public void setAlbum(String album) {
        this.album = album;
    }

    public String getBySomeBody() {
        return bySomeBody;
    }

    public void setBySomeBody(String bySomeBody) {
        this.bySomeBody = bySomeBody;
    }

    public String getOffset() {
        return offset;
    }

    public void setOffset(String offset) {
        this.offset = offset;
    }

    public ArrayList<LrcList> getLrcLists() {
        return lrcLists;
    }

    public void setLrcLists(ArrayList<LrcList> lrcLists) {
        this.lrcLists = lrcLists;
    }
}

然後在到MusicService服務類裡面呼叫

Handler handler = new Handler() {
    };
public void initLrc(String path) {

        LrcInfo mlrcInfo = new LrcInfo();
        //建立歌詞物件
       LrcParse lrcParser = new LrcParse(path);
        //讀歌詞,並將資料傳給歌詞資訊類
       mlrcInfo = lrcParser.readLrc();
        //獲得歌詞中的結點
        lrcLists = mlrcInfo.getLrcLists();
        //在MainActivity裡面設定靜態來共享資料
        MainActivity.lrcView.setmLrcList(mlrcInfo);
        //切換帶動畫顯示歌詞
        MainActivity.lrcView.setAnimation(AnimationUtils.loadAnimation(MusicService.this, R.anim.alpha_z));
        handler.post(mRunnable);
    }

    Runnable mRunnable = new Runnable() {

        @Override
        public void run() {
            MainActivity.lrcView.setIndex(lrcIndex());
            MainActivity.lrcView.invalidate();
            handler.postDelayed(mRunnable, 100);
        }
    };


    public int lrcIndex() {
        if (mediaPlayer.isPlaying()) {
            curplaytime2 = mediaPlayer.getCurrentPosition();
            duration2 = mediaPlayer.getDuration();
        }
        if (curplaytime2 < duration2) {
            for (int i = 0; i < lrcLists.size(); i++) {
                if (i < lrcLists.size() - 1) {
                    if (curplaytime2 < lrcLists.get(i).getCurrentTime() && i == 0) {
                        index = i;
                    }
                    if ((curplaytime2 > lrcLists.get(i).getCurrentTime())&& curplaytime2 < lrcLists.get(i+1).getCurrentTime()) {
                        index = i;
                    }
                }
                if ((i == lrcLists.size() - 1)&& curplaytime2 > lrcLists.get(i).getCurrentTime()) {
                    index = i;
                }
            }
        }
        return index;
    }

MainActivity就是主活動介面,在介面初始化自定義控制元件,當然也要在佈局檔案裡面加上佈局。R.anim.alpha_z 這個我也不知道是效果,所以不寫了
歌詞檔案可以自己製作哦,在百度裡面搜尋lrc格式的歌詞,然後自己新建一個資料夾,改一下字尾.lrc,當然檔名要跟歌曲名一樣
摘抄自http://blog.csdn.net/wwj_748/article/details/9006567