Android自定义控件——歌词显示

这段时间在写一个音乐播放器,需要显示歌词,下面是我写的一个歌词显示的view。目前它已经可以完成歌词的基本显示,细节地方后期继续完善。

MainActivity从资源文件读入歌词,歌曲,并利用正则表达式解析歌词变为我们想要的格式。解析之后得到两个list: timeList 和 contentList。我们把这两个list传入LrcView中,然后显示。
歌词是下载百度音乐的歌词解析的,我觉得自己写的很麻烦。如果大家有更好的方法可以留言告诉我。下面是歌词的原本格式。
Android自定义控件——歌词显示_第1张图片
解析之后的格式:Android自定义控件——歌词显示_第2张图片
下面是代码部分
1:MainActivity

import android.media.MediaPlayer;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MainActivity extends AppCompatActivity {
    MediaPlayer mediaPlayer = new MediaPlayer();
    private LrcView lrcView = null;
    private List timeList = new ArrayList<>();
    private List contentList = new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        InputStream inputStream =getResources().openRawResource(R.raw.apologize);//从资源文件里面得到输入流
        AnalyseLyricFile(inputStream);
        Log.e("size",""+timeList.size());
        mediaPlayer = MediaPlayer.create(this, R.raw.appolo);

        lrcView = (LrcView) super.findViewById(R.id.lyric_show);
        lrcView.setList(timeList,contentList);
        lrcView.init();
        new Thread(lrcView).start();

        mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {

            @Override
            public void onCompletion(MediaPlayer mp) {
                mediaPlayer.release();//歌曲播放完释放mediaplayer
            }
        });

        mediaPlayer.start();//开始播放
    }

    public void AnalyseLyricFile(InputStream inputStream){ //参数是歌词文件的路径
        BufferedReader reader = null;
        InputStreamReader inputFileReader = null;
        String tempString = null;
        //正则表达式解析出时间戳
        Pattern timePattern = Pattern.compile("(.*?)]");
        String time = "";
        long timestamp = 0;
        long timePadding = 0;//帮助得到每行歌词显示时间的变量
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");//把字符串转换为时间
        try {
            inputFileReader = new InputStreamReader(inputStream, "utf-8");
            reader = new BufferedReader(inputFileReader);
            // 一次读入一行,直到读入null为文件结束
            while ((tempString = reader.readLine()) != null) {
                Matcher timeMatcher = timePattern.matcher(tempString);
                if (timeMatcher.find()){//如果匹配到符合结果
                    time = timeMatcher.group(1);//不要后面的中括号
                    if((int)time.charAt(1) <= 57){//非数字选项,目前没有分析音乐的标题,作曲家
                        time = time.replace('.', ':');
                        time = time.substring(1, time.length());
                        String temp [] = time.split(":");
                        try {
                            timestamp = simpleDateFormat.parse("1970010108"+temp[0]+temp[1]).getTime();//电脑的开始计时时间是从1970年1月1日早上8点钟开始
                            timestamp+=10*Integer.parseInt(temp[2]);
                            timeList.add(timestamp-timePadding);
                            contentList.add(" "+tempString.substring(10, tempString.length()));
                            timePadding = timestamp;
                        } catch (ParseException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e1) {
                }
            }
        }
    }
}

这是具体显示的代码
2:LrcView代码

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.util.DisplayMetrics;
import android.util.Log;
import android.view.View;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Queue;


public class LrcView extends View implements Runnable{
    private int width = 1080;//xml中设定的歌词宽度
    private int heght = 1000;//xml中设定的歌词高度
    private Paint paint1 = null;//用于绘画当前正在播放的歌词
    private Paint paint2 = null;//用于绘画非当前播放的歌词

    private int padding = 100;//歌词的行间距
    private int textSize = 18;
    private int index = 1;//正在播放歌词段所在下标
    private int lines = 1;//总共要显示多少行歌词
    private int count = 0;//记录应该取哪一列歌词

    private boolean hasLyric = true;

    private List timeList = new ArrayList<>();
    private List contentList = new ArrayList<>();
    private Queue queue = new ArrayDeque();//用于储存当前正在展示的歌词,只显示十行的内容

    /**
     * 歌词显示时间相关的参数
     */
    private long timePastBy = 0;//歌词已经显示的时间

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

    public void init(){//初始化歌词是通过给这个view一个 String list
        count = 0;
        if(contentList.size()== 0){//没有歌词
            contentList.add("Just enjoy!");
        }
        setFocusable(true);
        lines = heght/padding;//得到可以显示多少行歌词
        index = lines/2;//正在播放歌词的所在下标

        for(int i = 0;i//把队列初始化为空
            queue.add("");
        }

        for (int i = 0;i//开始播放的时候,第一行歌词需要在中间出现
            contentList.add("");
            queue.remove();
            queue.add(contentList.get(count));
            count++;
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        paint1 = new Paint();
        paint1.setAntiAlias(true);
        paint1.setTextAlign(Paint.Align.CENTER);

        paint2 = new Paint();
        paint2.setAntiAlias(true);
        paint2.setTextAlign(Paint.Align.CENTER);

        paint1.setColor(Color.argb(210,255,248,255));//透明度以及RGB值
        paint2.setColor(Color.argb(140,200,200,200));

        paint1.setTextSize(50);//被播放的歌词字体设置为50px
        paint1.setTypeface(Typeface.SERIF);

        paint2.setTextSize(40);
        paint2.setTypeface(Typeface.DEFAULT);

        //设置歌词之间的行距,根据显示时间,显示歌词
        int lineCount = 1;
        for(String s:queue){
            if(lineCount == index)
                canvas.drawText(s,width/2,200+padding*lineCount,paint1);//如果是正在播放的歌词,字体则设为白色
            else
                canvas.drawText(s,width/2,200+padding*lineCount,paint2);
            lineCount++;
        }

    }

    public void move(){
        //歌词滚动
        if(count//如果还有剩余歌词
            queue.remove();//queue里面动态更新,让歌词会滚动
            queue.add(contentList.get(count));
            count++;
            postInvalidate();//刷新界面
        }else{
            return;
        }

    }

    @Override
    public void run() {
        while(true){
            try{
                if (timeList.size()>0) {
                    timePastBy+=timeList.get(0);//歌词已经显示了多久,为调整歌词进度设定(目前还没有添加这个功能)
                    Thread.sleep(timeList.remove(0));//每行歌词显示的时间
                    move();
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    public void setList(List l1,List l2){
        timeList = l1;
        contentList = l2;
    }
}

3:activity_main


<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_main"
    android:orientation="vertical"
    android:background="@drawable/bg"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <com.example.xiaojun.lyricviewtest.LrcView
        android:id="@+id/lyric_show"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />
LinearLayout>

这是最终效果图:
Android自定义控件——歌词显示_第3张图片

源代码链接源码

你可能感兴趣的:(android,android)