package io.hefuyi.listener.widget;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.OvershootInterpolator;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class LyricView extends View {
private int mBtnColor = Color.parseColor("#EFEFEF"); // 按钮颜色
private int mHintColor = Color.parseColor("#FFFFFF"); // 提示语颜色
private int mDefaultColor = Color.parseColor("#FFFFFF"); // 默认字体颜色
private int mIndicatorColor = Color.parseColor("#EFEFEF"); // 指示器颜色
private int mHighLightColor = Color.parseColor("#4FC5C7"); // 当前播放位置的颜色
private int mCurrentShowColor = Color.parseColor("#AAAAAA"); // 当前拖动位置的颜色
private int mLineCount; // 行数
private float mLineHeight; // 行高
private float mScrollY = 0; // 纵轴偏移量
private float mVelocity = 0; // 纵轴上的滑动速度
private float mLineSpace = 0; // 行间距(包含在行高中)
private float mShaderWidth = 0; // 渐变过渡的距离
private int mCurrentShowLine = 0; // 当前拖动位置对应的行数
private int mCurrentPlayLine = 0; // 当前播放位置对应的行数
private int mMinStartUpSpeed = 1600; // 最低滑行启动速度
private boolean mUserTouch = false; // 判断当前用户是否触摸
private boolean mIndicatorShow = false; // 判断当前滑动指示器是否显示
private boolean mIsMoved = false;//判断用户触摸时是否发生move事件
private boolean mPlayerClick = false; //判断当前用户是否点击指示器
/***/
private int mBtnWidth = 0; // Btn 按钮的宽度
private int mDefaultMargin = 12;
private int maximumFlingVelocity; // 最大纵向滑动速度
private Rect mBtnBound, mTimerBound;
private VelocityTracker mVelocityTracker;
private LyricInfo mLyricInfo;
private String mDefaultTime = "00:00";
private String mDefaultHint = "暂无歌词";
private Paint mTextPaint, mBtnPaint, mIndicatorPaint;
private OnPlayerClickListener mClickListener;
private final int MSG_PLAYER_SLIDE = 0x158;
private final int MSG_PLAYER_HIDE = 0x157;
private ValueAnimator mFlingAnimator;
private boolean mPlayable = false;
private boolean mSliding = false;
private boolean mTouchable = true;
public LyricView(Context context) {
super(context);
initMyView(context);
}
public LyricView(Context context, AttributeSet attrs) {
super(context, attrs);
initMyView(context);
}
public LyricView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initMyView(context);
}
private void initMyView(Context context) {
maximumFlingVelocity = ViewConfiguration.get(context).getScaledMaximumFlingVelocity();
initAllPaints();
initAllBounds();
}
/**
* 初始化需要的尺寸
* */
private void initAllBounds() {
setTextSize(15);
setLineSpace(12);
mBtnWidth = (int) (getRawSize(TypedValue.COMPLEX_UNIT_SP, 24));
mTimerBound = new Rect();
mIndicatorPaint.getTextBounds(mDefaultTime, 0, mDefaultTime.length(), mTimerBound);
measureLineHeight();
}
/**
* 初始化画笔
* */
private void initAllPaints() {
mTextPaint = new Paint();
mTextPaint.setDither(true);
mTextPaint.setAntiAlias(true);
mTextPaint.setTextAlign(Paint.Align.CENTER);
mIndicatorPaint = new Paint();
mIndicatorPaint.setDither(true);
mIndicatorPaint.setAntiAlias(true);
mIndicatorPaint.setTextSize(getRawSize(TypedValue.COMPLEX_UNIT_SP, 12));
mIndicatorPaint.setTextAlign(Paint.Align.CENTER);
mBtnPaint = new Paint();
mBtnPaint.setDither(true);
mBtnPaint.setAntiAlias(true);
mBtnPaint.setColor(mBtnColor);
mBtnPaint.setStrokeWidth(3.0f);
mBtnPaint.setStyle(Paint.Style.STROKE);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mShaderWidth = getMeasuredHeight() * 0.3f;
}
@Override
protected void onDraw(Canvas canvas) {
if(mLyricInfo != null && mLyricInfo.song_lines != null && mLyricInfo.song_lines.size() > 0) {
for(int i = 0, size = mLineCount; i < size; i ++) {
float x = getMeasuredWidth() * 0.5f;
float y = getMeasuredHeight() * 0.5f + (i + 0.5f) * mLineHeight - 6 - mLineSpace * 0.5f - mScrollY;
if(y + mLineHeight * 0.5f < 0) {
continue;
}
if(y - mLineHeight * 0.5f > getMeasuredHeight()) {
break;
}
if(i == mCurrentPlayLine - 1) {
mTextPaint.setColor(mHighLightColor);
} else {
if(mIndicatorShow && i == mCurrentShowLine - 1) {
mTextPaint.setColor(mCurrentShowColor);
}else {
mTextPaint.setColor(mDefaultColor);
}
}
if(y > getMeasuredHeight() - mShaderWidth || y < mShaderWidth) {
if(y < mShaderWidth) {
mTextPaint.setAlpha(26 + (int) (23000.0f * y / mShaderWidth * 0.01f));
} else {
mTextPaint.setAlpha(26 + (int) (23000.0f * (getMeasuredHeight() - y) / mShaderWidth * 0.01f));
}
} else {
mTextPaint.setAlpha(255);
}
canvas.drawText(mLyricInfo.song_lines.get(i).content, x, y, mTextPaint);
}
} else {
mTextPaint.setColor(mHintColor);
canvas.drawText(mDefaultHint, getMeasuredWidth() * 0.5f, (getMeasuredHeight() + mLineHeight - 6) * 0.5f, mTextPaint);
}
/**
* 滑动提示部分内容绘制
* */
if(mIndicatorShow && scrollable()) {
if(mPlayable) {
drawPlayer(canvas);
drawIndicator(canvas);
}
}
}
/**
* 绘制左侧的播放按钮
* @param canvas
* */
private void drawPlayer(Canvas canvas) {
mBtnBound = new Rect(mDefaultMargin, (int) (getMeasuredHeight() * 0.5f - mBtnWidth * 0.5f), mBtnWidth + mDefaultMargin, (int) (getMeasuredHeight() * 0.5f + mBtnWidth * 0.5f));
Path path = new Path();
float radio = mBtnBound.width() * 0.3f;
float value = (float) Math.sqrt(Math.pow(radio, 2) - Math.pow(radio * 0.5f, 2));
path.moveTo(mBtnBound.centerX() - radio * 0.5f, mBtnBound.centerY() - value);
path.lineTo(mBtnBound.centerX() - radio * 0.5f, mBtnBound.centerY() + value);
path.lineTo(mBtnBound.centerX() + radio, mBtnBound.centerY());
path.lineTo(mBtnBound.centerX() - radio * 0.5f, mBtnBound.centerY() - value);
mBtnPaint.setAlpha(128);
canvas.drawPath(path, mBtnPaint); // 绘制播放按钮的三角形
canvas.drawCircle(mBtnBound.centerX(), mBtnBound.centerY(), mBtnBound. width() * 0.48f, mBtnPaint); // 绘制圆环
}
/**
* 绘制指示器
* @param canvas
* */
private void drawIndicator(Canvas canvas) {
mIndicatorPaint.setColor(mIndicatorColor);
mIndicatorPaint.setAlpha(128);
mIndicatorPaint.setStyle(Paint.Style.FILL);
canvas.drawText(measureCurrentTime(), getMeasuredWidth() - mTimerBound.width(), (getMeasuredHeight() + mTimerBound.height() - 6) * 0.5f, mIndicatorPaint);
Path path = new Path();
mIndicatorPaint.setStrokeWidth(2.0f);
mIndicatorPaint.setStyle(Paint.Style.STROKE);
mIndicatorPaint.setPathEffect(new DashPathEffect(new float[]{20, 10}, 0));
path.moveTo(mPlayable ? mBtnBound.right + 24 : 24 , getMeasuredHeight() * 0.5f);
path.lineTo(getMeasuredWidth() - mTimerBound.width() - mTimerBound.width() - 36, getMeasuredHeight() * 0.5f);
canvas.drawPath(path , mIndicatorPaint);
}
/**
* 计算行高度
* */
private void measureLineHeight() {
Rect lineBound = new Rect();
mTextPaint.getTextBounds(mDefaultHint, 0, mDefaultHint.length(), lineBound);
mLineHeight = lineBound.height() + mLineSpace;
}
/**
* 获取当前滑动到的位置的当前时间
* */
private String measureCurrentTime() {
DecimalFormat format = new DecimalFormat("00");
if(mLyricInfo != null && mLineCount > 0 && mCurrentShowLine - 1 < mLineCount && mCurrentShowLine > 0) {
return format.format(mLyricInfo.song_lines.get(mCurrentShowLine - 1).start / 1000 / 60) + ":" + format.format(mLyricInfo.song_lines.get(mCurrentShowLine - 1).start / 1000 % 60);
}
if(mLyricInfo != null && mLineCount > 0 && (mCurrentShowLine - 1) >= mLineCount) {
return format.format(mLyricInfo.song_lines.get(mLineCount - 1).start / 1000 / 60) + ":" + format.format(mLyricInfo.song_lines.get(mLineCount - 1).start / 1000 % 60);
}
if(mLyricInfo != null && mLineCount > 0 && mCurrentShowLine - 1 <= 0) {
return format.format(mLyricInfo.song_lines.get(0).start / 1000 / 60) + ":" + format.format(mLyricInfo.song_lines.get(0).start / 1000 % 60);
}
return mDefaultTime;
}
private float mDownX, mDownY, mLastScrollY; // 记录手指按下时的坐标和当前的滑动偏移量
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_MOVE:
getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_UP:
break;
default:
break;
}
return super.dispatchTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if(!mTouchable){
return super.onTouchEvent(event);
}
if(mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(event);
switch (event.getAction()) {
case MotionEvent.ACTION_CANCEL:
actionCancel(event);
break;
case MotionEvent.ACTION_DOWN:
actionDown(event);
break;
case MotionEvent.ACTION_MOVE:
actionMove(event);
break;
case MotionEvent.ACTION_UP:
actionUp(event);
break;
default:
break;
}
invalidateView();
if (mIsMoved || mPlayerClick) {
return true;
} else {
return super.onTouchEvent(event);
}
}
/**
* 手势取消执行事件
* @param event
* */
private void actionCancel(MotionEvent event) {
releaseVelocityTracker();
}
/**
* 手势按下执行事件
* @param event
* */
private void actionDown(MotionEvent event) {
postman.removeMessages(MSG_PLAYER_SLIDE);
postman.removeMessages(MSG_PLAYER_HIDE);
mLastScrollY = mScrollY;
mDownX = event.getX();
mDownY = event.getY();
if(mFlingAnimator != null) {
mFlingAnimator.cancel();
mFlingAnimator = null;
}
setUserTouch(true);
mIsMoved = false;
mPlayerClick = false;
}
/**
* 手势移动执行事件
* @param event
* */
private void actionMove(MotionEvent event) {
if(scrollable()) {
final VelocityTracker tracker = mVelocityTracker;
tracker.computeCurrentVelocity(1000, maximumFlingVelocity);
float scrollY = mLastScrollY + mDownY - event.getY(); // 102 -2 58 42
float value01 = scrollY - (mLineCount * mLineHeight * 0.5f); // 52 -52 8 -8
float value02 = ((Math.abs(value01) - (mLineCount * mLineHeight * 0.5f))); // 2 2 -42 -42
mScrollY = value02 > 0 ? scrollY - (measureDampingDistance(value02) * value01 / Math.abs(value01)) : scrollY; // value01 / Math.abs(value01) 控制滑动方向
mVelocity = tracker.getYVelocity();
measureCurrentLine();
if (Math.abs(mVelocity) > 1) {
mIsMoved = true;
}
}
}
/**
* 计算阻尼效果的大小
* */
private final int mMaxDampingDistance = 360;
private float measureDampingDistance(float value02) {
return value02 > mMaxDampingDistance ? (mMaxDampingDistance * 0.6f + (value02 - mMaxDampingDistance) * 0.72f) : value02 * 0.6f;
}
/**
* 手势抬起执行事件
* */
private void actionUp(MotionEvent event) {
releaseVelocityTracker();
// 2.4s 后发送一个指示器隐藏的请求
postman.sendEmptyMessageDelayed(MSG_PLAYER_HIDE, 2400);
if (scrollable()) {
setUserTouch(false); // 用户手指离开屏幕,取消触摸标记
if (overScrolled() && mScrollY < 0) {
smoothScrollTo(0);
return;
}
if (overScrolled() && mScrollY > mLineHeight * (mLineCount - 1)) {
smoothScrollTo(mLineHeight * (mLineCount - 1));
return;
}
if (Math.abs(mVelocity) > mMinStartUpSpeed) {
doFlingAnimator(mVelocity);
return;
}
if (mIndicatorShow && clickPlayer(event)) {
if (mCurrentShowLine != mCurrentPlayLine) {
mIndicatorShow = false;
mPlayerClick = true;
if (mClickListener != null) {
mClickListener.onPlayerClicked(mLyricInfo.song_lines.get(mCurrentShowLine - 1).start, mLyricInfo.song_lines.get(mCurrentShowLine - 1).content);
}
}
}
} else {
performClick();
}
}
/**
* 刷新View
* */
private void invalidateView() {
if(Looper.getMainLooper() == Looper.myLooper()) {
// 当前线程是主UI线程,直接刷新。
invalidate();
} else {
// 当前线程是非UI线程,post刷新。
postInvalidate();
}
}
/**
* 设置用户是否触摸的标记
* @param isUserTouch 标记用户是否触摸屏幕
* */
private void setUserTouch(boolean isUserTouch) {
if(mUserTouch == isUserTouch) {
return;
}
mUserTouch = isUserTouch;
if(isUserTouch) {
mIndicatorShow = isUserTouch;
}
}
/**
* 释放速度追踪器
* */
private void releaseVelocityTracker() {
if(null != mVelocityTracker) {
mVelocityTracker.clear();
mVelocityTracker.recycle();
mVelocityTracker = null;
}
}
/**
* 滑行动画
* @param velocity 滑动速度
* */
private void doFlingAnimator(float velocity) {
//注: Math.abs(velocity) < = 16000
float distance = (velocity / Math.abs(velocity) * Math.min((Math.abs(velocity) * 0.050f), 640)); // 计算就已当前的滑动速度理论上的滑行距离是多少
float to = Math.min(Math.max(0, (mScrollY - distance)), (mLineCount - 1) * mLineHeight); // 综合考虑边界问题后得出的实际滑行距离
mFlingAnimator = ValueAnimator.ofFloat(mScrollY, to);
mFlingAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mScrollY = (float) animation.getAnimatedValue();
measureCurrentLine();
invalidateView();
}
});
mFlingAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
mVelocity = mMinStartUpSpeed - 1;
mSliding = true;
}
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
mSliding = false;
}
@Override
public void onAnimationCancel(Animator animation) {
super.onAnimationCancel(animation);
}
});
mFlingAnimator.setDuration(420);
mFlingAnimator.setInterpolator(new DecelerateInterpolator());
mFlingAnimator.start();
}
/**
* To measure current showing line number based on the view's scroll Y
* */
private void measureCurrentLine() {
float baseScrollY = mScrollY + mLineHeight * 0.5f;
mCurrentShowLine = (int) (baseScrollY / mLineHeight + 1);
}
/**
* Input current showing line to measure the view's current scroll Y
* @param line 当前指定行号
* */
private float measureCurrentScrollY(int line) {
return (line - 1) * mLineHeight;
}
/**
* 判断当前点击事件是否落在播放按钮触摸区域范围内
* @param event 触摸事件
* */
private boolean clickPlayer(MotionEvent event) {
if(mBtnBound != null && mDownX > (mBtnBound.left - mDefaultMargin) && mDownX < (mBtnBound.right + mDefaultMargin) && mDownY > (mBtnBound.top - mDefaultMargin) && mDownY < (mBtnBound.bottom + mDefaultMargin)) {
float upX = event.getX(); float upY = event.getY();
return upX > (mBtnBound.left - mDefaultMargin) && upX < (mBtnBound.right + mDefaultMargin) && upY > (mBtnBound.top - mDefaultMargin) && upY < (mBtnBound.bottom + mDefaultMargin);
}
return false;
}
/**
* 从当前位置滑动到指定位置上
* @param toY 指定纵坐标位置
* */
private void smoothScrollTo(float toY) {
final ValueAnimator animator = ValueAnimator.ofFloat(mScrollY , toY);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
if(mUserTouch) {
animator.cancel();
return;
}
mScrollY = (float) animation.getAnimatedValue();
invalidateView();
}
});
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
mSliding = true;
}
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
mSliding = false;
measureCurrentLine();
invalidateView();
}
});
animator.setDuration(640);
animator.setInterpolator(new OvershootInterpolator(0.5f));
animator.start();
}
/**
* 判断是否可以进行滑动
* */
private boolean scrollable() {
return mLyricInfo != null && mLyricInfo.song_lines != null && mLyricInfo.song_lines.size() > 0;
}
/**
* 判断当前View是否已经滑动到歌词的内容区域之外
* */
private boolean overScrolled() {
return scrollable() && (mScrollY > mLineHeight * (mLineCount - 1) || mScrollY < 0);
}
Handler postman = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case MSG_PLAYER_HIDE:
postman.sendEmptyMessageDelayed(MSG_PLAYER_SLIDE, 1200);
mIndicatorShow = false;
invalidateView();
case MSG_PLAYER_SLIDE:
smoothScrollTo(measureCurrentScrollY(mCurrentPlayLine));
invalidateView();
}
}
};
/**
* 根据当前给定的时间戳滑动到指定位置
* @param time 时间戳
* */
private void scrollToCurrentTimeMillis(long time) {
int position = 0;
if(scrollable()) {
for(int i = 0, size = mLineCount; i < size; i ++) {
LineInfo lineInfo = mLyricInfo.song_lines.get(i);
if(lineInfo != null && lineInfo.start > time) {
position = i;
break;
}
if(i == mLineCount - 1) {
position = mLineCount;
}
}
}
if(mCurrentPlayLine != position && !mUserTouch && !mSliding && !mIndicatorShow) {
mCurrentPlayLine = position;
smoothScrollTo(measureCurrentScrollY(position));
} else {
if(!mSliding && !mIndicatorShow) {
mCurrentPlayLine = mCurrentShowLine = position;
}
}
}
/**
* 初始化歌词信息
* @param inputStream 歌词文件的流信息
* */
private void setupLyricResource(InputStream inputStream, String charsetName) {
if(inputStream != null) {
try {
LyricInfo lyricInfo = new LyricInfo();
lyricInfo.song_lines = new ArrayList<>();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, charsetName);
BufferedReader reader = new BufferedReader(inputStreamReader);
String line = null;
while((line = reader.readLine()) != null) {
analyzeLyric(lyricInfo, line);
}
//歌词排序
Collections.sort(lyricInfo.song_lines,new sort());
reader.close();
inputStream.close();
inputStreamReader.close();
mLyricInfo = lyricInfo;
mLineCount = mLyricInfo.song_lines.size();
invalidateView();
} catch (IOException e) {
e.printStackTrace();
}
} else {
mDefaultHint = "暂无歌词";
invalidateView();
}
}
/**
* 逐行解析歌词内容
* */
private void analyzeLyric(LyricInfo lyricInfo, String line) {
int index = line.indexOf("]");
if(line != null && line.startsWith("[offset:")) {
// 时间偏移量
String string = line.substring(8, index).trim();
lyricInfo.song_offset = Long.parseLong(string);
return;
}
if(line != null && line.startsWith("[ti:")) {
// title 标题
String string = line.substring(4, index).trim();
lyricInfo.song_title = string;
return;
}
if(line != null && line.startsWith("[ar:")) {
// artist 作者
String string = line.substring(4, index).trim();
lyricInfo.song_artist = string;
return;
}
if(line != null && line.startsWith("[al:")) {
// album 所属专辑
String string = line.substring(4, index).trim();
lyricInfo.song_album = string;
return;
}
if(line != null && line.startsWith("[by:")) {
return;
}
if(line != null && index == 9 && line.trim().length() > 10) {
// 歌词内容,需要考虑一行歌词有多个时间戳的情况
int lastIndexOfRightBracket = line.lastIndexOf("]");
String content = line.substring(lastIndexOfRightBracket + 1, line.length());
String times = line.substring(0,lastIndexOfRightBracket + 1).replace("[", "-").replace("]", "-");
String arrTimes[] = times.split("-");
for(String temp : arrTimes){
if(temp.trim().length() == 0){
continue;
}
/** [02:34.14][01:07.00]当你我不小心又想起她
*
上面的歌词的就可以拆分为下面两句歌词了
[02:34.14]当你我不小心又想起她
[01:07.00]当你我不小心又想起她
*/
LineInfo lineInfo = new LineInfo();
lineInfo.content = content;
lineInfo.start = measureStartTimeMillis(temp);
lyricInfo.song_lines.add(lineInfo);
}
}
}
/**
* 将解析得到的表示时间的字符转化为Long型
*/
private static long measureStartTimeMillis(String timeString){
//因为给如的字符串的时间格式为XX:XX.XX,返回的long要求是以毫秒为单位
//将字符串 XX:XX.XX 转换为 XX:XX:XX
timeString = timeString.replace('.', ':');
//将字符串 XX:XX:XX 拆分
String[] times = timeString.split(":");
// mm:ss:SS
return Integer.valueOf(times[0]) * 60 * 1000 +//分
Integer.valueOf(times[1]) * 1000 +//秒
Integer.valueOf(times[2]) ;//毫秒
}
/**
* 重置歌词内容
* */
private void resetLyricInfo() {
if(mLyricInfo != null) {
if(mLyricInfo.song_lines != null) {
mLyricInfo.song_lines.clear();
mLyricInfo.song_lines = null;
}
mLyricInfo = null;
}
}
/**
* 初始化控件
* */
private void resetView() {
mCurrentPlayLine = mCurrentShowLine = 0;
resetLyricInfo();
invalidateView();
mLineCount = 0;
mScrollY = 0;
}
class LyricInfo {
List<LineInfo> song_lines;
String song_artist; // 歌手
String song_title; // 标题
String song_album; // 专辑
long song_offset; // 偏移量
}
class LineInfo {
String content; // 歌词内容
long start; // 开始时间
}
class sort implements Comparator<LineInfo> {
@Override
public int compare(LineInfo lrc, LineInfo lrc2) {
if(lrc.start<lrc2.start){
return -1;
}else if ((lrc.start>lrc2.start)){
return 1;
}else {
return 0;
}
}
}
public interface OnPlayerClickListener {
void onPlayerClicked(long progress, String content);
}
private void setRawTextSize(float size) {
if (size != mTextPaint.getTextSize()) {
mTextPaint.setTextSize(size);
measureLineHeight();
mScrollY = measureCurrentScrollY(mCurrentPlayLine);
invalidateView();
}
}
private float getRawSize(int unit, float size) {
Context context = getContext();
Resources resources;
if (context == null) {
resources = Resources.getSystem();
} else {
resources = context.getResources();
}
return TypedValue.applyDimension(unit, size, resources.getDisplayMetrics());
}
/**
* ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ *
* 对外API *
* ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ *
* */
/**
* 设置当前时间显示位置
* @param current 时间戳
* */
public void setCurrentTimeMillis(long current) {
scrollToCurrentTimeMillis(current);
}
/**
* 设置歌词文件
* @param file 歌词文件
* @param charsetName 解析字符集
* */
public void setLyricFile(File file, String charsetName) {
if(file != null && file.exists()) {
try {
setupLyricResource(new FileInputStream(file), charsetName);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
} else {
mDefaultHint = "暂无歌词";
invalidateView();
}
}
/**
* 设置播放按钮点击监听事件
* @param mClickListener 监听器
* */
public void setOnPlayerClickListener(OnPlayerClickListener mClickListener) {
this.mClickListener = mClickListener;
}
/**
* 重置、设置歌词内容被重置后的提示内容
* @param message 提示内容
* */
public void reset(String message) {
mDefaultHint = message;
resetView();
}
/**
* 设置高亮显示文本的字体颜色
* @param color 颜色值
* */
public void setHighLightTextColor(int color) {
if(mHighLightColor != color) {
mHighLightColor = color;
invalidateView();
}
}
public void setDefaultColor(int color) {
if (mDefaultColor != color) {
mDefaultColor = color;
invalidateView();
}
}
public int getDefaultColor() {
return mDefaultColor;
}
/**
* 设置歌词内容行间距
* @param lineSpace 行间距大小
* */
public void setLineSpace(float lineSpace) {
if(mLineSpace != lineSpace) {
mLineSpace = getRawSize(TypedValue.COMPLEX_UNIT_SP, lineSpace);
measureLineHeight();
mScrollY = measureCurrentScrollY(mCurrentPlayLine);
invalidateView();
}
}
/**
* 设置歌词文本内容字体大小
* @param unit
* @param size
* */
public void setTextSize(int unit, float size) {
setRawTextSize(getRawSize(unit, size));
}
/**
* 设置歌词文本内容字体大小
* @param size
* */
public void setTextSize(float size) {
setTextSize(TypedValue.COMPLEX_UNIT_SP, size);
}
public void setPlayable(boolean playable) {
mPlayable = playable;
}
public void setTouchable(boolean touchable) {
mTouchable = touchable;
}
public void setHintColor(int color){
if (mHintColor != color) {
mHintColor = color;
invalidate();
}
}
}