手机影音项目笔记(四)---音乐播放歌词的控件的自定义

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;
    }
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值