Android 自定义歌词滚动

Android 自定义歌词滚动

1丶在配置清单当中加入权限:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

2丶在Assets里面加入歌和歌词:

     (  看自己喜欢什么歌)

MainActivity

package com.example.lyricdemo;

import java.util.List;
import com.example.lyricdemo.LrcView.MedCallBack;
import android.R.plurals;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.app.Activity;
import android.content.res.AssetFileDescriptor;
import android.view.Menu;

public class MainActivity extends Activity implements MedCallBack{

private LrcRows lrcRows=new LrcRows();
private MediaPlayer mediaPlayer=new MediaPlayer();
private boolean timeFlag=true;
private LrcView lrcView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        initview();
    }
    Handler handler=new Handler(){
    public void handleMessage(android.os.Message msg) {
    if (msg.what==0) {
int time=mediaPlayer.getCurrentPosition();
lrcView.LrcToPlayer(time);//根据播放的进度,时时跟新歌词
}
    };
    };
    
Thread thread=new Thread(new Runnable() {

@Override
public void run() {
// TODO Auto-generated method stub
while (timeFlag) {

try {
Thread.sleep(1000);
} catch (Exception e) {

}
handler.sendEmptyMessage(0);
}
}
});


private void initview() {
// TODO Auto-generated method stub
List<LrcRow>list=lrcRows.BuildList(this);
lrcView = (LrcView)findViewById(R.id.mylrcview);
lrcView.setLrc(list);
lrcView.setCall(this);

try {
//从assets打开
AssetFileDescriptor fileDescriptor=getAssets().openFd("farawayfromhome.mp3");

mediaPlayer.setDataSource(fileDescriptor.getFileDescriptor(),fileDescriptor.getStartOffset(),fileDescriptor.getLength());
mediaPlayer.prepare();
mediaPlayer.start();
thread.start();
} catch (Exception e) {
// TODO: handle exception
}
}



//歌曲播放时,根据拖动跨越的行数里面的时间快进或快退带时间对应的播放进度
@Override
public void call(long time) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.seekTo((int) time);
}

}

@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
timeFlag=false;
mediaPlayer.stop();
}  
}

LrcView

package com.example.lyricdemo;
import java.util.List;
import android.R.bool;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class LrcView extends View{

private Paint paint;//画笔
private List<LrcRow>list;//歌词数据源
private int nowColor=Color.YELLOW;//正在播放的歌词颜色
private int normalColor=Color.WHITE;//其他歌词的颜色
private int lineColor=Color.CYAN;//分割线及时间显示的颜色
private float textSize=20f;//歌词字体的大小
private float timeSize=15f;//时间显示的大小
private int lineHeight=2;//分割线的高度
private int marginHeight=10;//歌词与歌词之间的间隔
private int height;//自定义视图的高度
private int width;//自定义视图的宽;
private int index=0;//正在播放的歌词的行数
private String tipstr="暂无歌词";//默认情况下的歌词
private boolean TouchFlag=false;//手指按下的标志:当手指滑动的时候,界面不进行刷新
//回调接口
private MedCallBack medCallBack;
private float lasty=0;//最后手指按下的坐标不

public LrcView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public LrcView(Context context, AttributeSet attrs) {
super(context, attrs);
//实例化画笔,  抗锯齿
paint=new Paint(Paint.ANTI_ALIAS_FLAG);

}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//getheight:获得界面内的高度    
//getgetMeasuredHeight:获得视图实际测量的高度
height=getMeasuredHeight();
width=getMeasuredWidth();
}

@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);

paint.reset();//重置画笔
paint.setColor(nowColor);
paint.setTextSize(textSize);
paint.setTextAlign(Align.CENTER);

if (list==null) {
canvas.drawText(tipstr, width/2, height/2-textSize,paint );
return;
}
if (list.size()==0) {
canvas.drawText(tipstr, width/2,height/2-textSize, paint);
return;
}
//绘制中间正在播放的歌词
canvas.drawText(list.get(index).row, width/2, height/2-textSize, paint);
//绘制中间的分割线
paint.reset();
paint.setColor(lineColor);

if (TouchFlag) {
canvas.drawLine(0, height/2-textSize, width, height/2-textSize+lineHeight, paint);
paint.setTextSize(timeSize);
paint.setTextAlign(Align.LEFT);
canvas.drawText(list.get(index).str_timer,0,height/2,paint);
}
//绘制普通的歌词
paint.reset();
paint.setColor(normalColor);
paint.setTextSize(textSize);
paint.setTextAlign(Align.CENTER);
//绘制正在播放歌词上面的歌词
int normalIndex=0;
int rowY=0;//每行歌词的Y值
normalIndex=index-1;
rowY=(int)(height/2-textSize*2-marginHeight);

while (normalIndex>=0&&rowY>-textSize) {

canvas.drawText(list.get(normalIndex).row,width/2, rowY, paint);
normalIndex--;
rowY=(int) (rowY-textSize-marginHeight);
}
//2.绘制播放歌词下面的歌词
normalIndex=index+1;
rowY=(int) (height/2+marginHeight);
while(normalIndex<list.size()&&rowY<(height+textSize)){
canvas.drawText(list.get(normalIndex).row, width/2, rowY, paint);
normalIndex++;
rowY=(int) (rowY+marginHeight+textSize);
}
}

@Override
public boolean onTouchEvent(MotionEvent event) {

if (list==null) {
return true;
}
if (list.size()==0) {
return true;
}
//手指按下
if (event.getAction()==MotionEvent.ACTION_DOWN) {
TouchFlag=true;//显示时间和分割线
lasty=event.getY();//获取你手按下的Y轴坐标

//手指滑动
}else if (event.getAction()==MotionEvent.ACTION_MOVE) {
float nowY=event.getY();//当前手指滑动到的Y值
float disY=nowY-lasty;//计算手指滑动的Y轴的距离

//判断滑动的距离跨越几行歌词
if (Math.abs(disY)>marginHeight) {
int num=(int)(Math.abs(disY)/(marginHeight+textSize));
if (num>=1) {
if (disY<0) {
//快进
index+=num;
index=Math.min(list.size()-1, index);
}else if (disY>0) {
//快退
index-=num;
index=Math.max(0,index);
}
}
}
lasty=nowY;
//手指抬起
}else if (event.getAction()==MotionEvent.ACTION_UP) {
TouchFlag=false;

//调用接口
if (medCallBack!=null) {
medCallBack.call(list.get(index).time);
}
}
invalidate();//刷新布局
return true;
}


//查找歌词的方法,根据播放的进度跟新歌词 ,根据传入的参数进行当前歌曲进度的跳播
public void LrcToPlayer(long time){
if (list==null) {
return;
}
if (list.size()==0) {
return;
}
if (TouchFlag) {
return;
}

//遍历整个歌词集合,寻找time的插入区间
for (int i = 0; i < list.size(); i++) {
LrcRow lrcRow=list.get(i);//当前的歌词对象
LrcRow lrcRow2=(i+1)>=list.size()?null:list.get(i+1);
if (time>lrcRow.time&&lrcRow2!=null&&time<lrcRow2.time) {
index=i;
break;
}
if (lrcRow2==null) {
index=list.size()-1;
}
}
invalidate();
}

public interface MedCallBack{
//接口回调吧时间回调到主啊抽屉activity中去更新歌曲播放进度
public void call(long time);
}
//设置歌词的方法
public void setLrc(List<LrcRow>list){
this.list=list;
}
public void setCall(MedCallBack medCallBack){
this.medCallBack=medCallBack;
}
}

LrcRows

package com.example.lyricdemo;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.content.res.AssetManager;

public class LrcRows {

private List<LrcRow>list=new ArrayList<LrcRow>();//存放每行歌词的集合
//获取list集合的方法,将每行的歌词添加到list集合中

public List<LrcRow>BuildList(Context context){

//获取assets的管理器
AssetManager assetManager=context.getAssets();
//打开assets下的指定文件,获取输入流

try {
InputStream inputStream=assetManager.open("farawayfromhome.lrc");
//将字节输入流转化为字符流
BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(inputStream));
String line=null;
while ((line=bufferedReader.readLine())!=null) {
LrcRow lrcRow=new LrcRow();//创建每行封装歌词的对象
//获取新的解析封装好的歌词 添加到集合中
LrcRow lrcRow2=lrcRow.getRow(line);

if (lrcRow2!=null) {
list.add(lrcRow2);
}
}
bufferedReader.close();
} catch (Exception e) {
// TODO: handle exception
}
return list;

}

}

LrcRow

package com.example.lyricdemo;
//每行歌词的封装类:每行歌词的javaBean
public class LrcRow {

public String row;//歌词
public String str_timer;//字符串格式的时间
public long time;//每行歌词的毫秒时间

//获取每行歌词的 及歌词解析的方法 
public LrcRow getRow(String str){
if (str==null) {
return null;
}
if (str.equals("")) {
return null;
}
//!=9,将 歌词中不是歌词的那部分给过滤掉,因为歌词的时间字符串格式都是第九个位置为]
if (str.indexOf("]")!=9) {//index of 返回指定字符串在str中第一次出现的索引
return null;
}
//获取每行的主题歌词

row=str.substring(str.indexOf("]")+1);
//获取字符串格式的歌词时间    截取的时候包含开头,不包含结尾
str_timer=str.substring(1,str.indexOf("]"));
//字符替换:. 替换成:---》给字符串分割的时候提供分割标志
String newTime=str_timer.replace(".", ":");
//字符串的分割:自动分割成一个string类型的数组
String[]arr=newTime.split(":");
//将字符串格式的时间转换为毫秒格式的时间
time=Integer.valueOf(arr[0])*60*1000+Integer.valueOf(arr[1])*1000+
Integer.valueOf(arr[2]);

return this;
}

}

//以下是xml布局:

activity_main

<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:background="#008AD4"
    tools:context=".MainActivity" >
    <com.example.lyricdemo.LrcView
        android:id="@+id/mylrcview"
        android:layout_height="match_parent"
        android:layout_width="match_parent"
        />
</RelativeLayout>



猜你喜欢

转载自blog.csdn.net/RcyYangYang/article/details/73485375