| | |
| | | package com.auto.lyric.widgets; |
| | | |
| | | import android.app.Activity; |
| | | import android.content.Context; |
| | | import android.graphics.Canvas; |
| | | import android.graphics.Color; |
| | | import android.graphics.Paint; |
| | | import android.graphics.Typeface; |
| | | import android.media.MediaPlayer; |
| | | import android.os.Bundle; |
| | | import android.os.Handler; |
| | | import android.util.AttributeSet; |
| | | import android.widget.TextView; |
| | | import android.util.Log; |
| | | import android.view.MotionEvent; |
| | | |
| | | import com.auto.lyric.R; |
| | | |
| | | import java.io.File; |
| | | import java.io.IOException; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | import com.auto.lyric.data.LyricObject; |
| | | import com.auto.lyric.data.LyricServer; |
| | | import com.auto.lyric.util.DeviceUtil; |
| | | |
| | | /** |
| | | * 歌词 |
| | | * Created by Runt (qingingrunt2010@qq.com) on 2022/4/30. |
| | | */ |
| | | public class LyricView extends androidx.appcompat.widget.AppCompatTextView { |
| | | private Paint mPaint; |
| | | private float mX; |
| | | private Paint mPathPaint; |
| | | public int index = 0; |
| | | private List<Sentence> list; |
| | | public float mTouchHistoryY; |
| | | private int mY; |
| | | private float middleY;// |
| | | private static final int DY = 40; // |
| | | |
| | | |
| | | private float mX; //屏幕X轴的中点,此值固定,保持歌词在X中间显示 |
| | | private float offsetY; //歌词在Y轴上的偏移量,此值会根据歌词的滚动变小 |
| | | private float touchY; //当触摸歌词View时,保存为当前触点的Y轴坐标 |
| | | private int lrcIndex=0; //保存歌词TreeMap的下标 |
| | | private int SIZEWORD=0;//显示歌词文字的大小值 |
| | | private int INTERVAL=45;//歌词每行的间隔 |
| | | Paint paint=new Paint();//画笔,用于画不是高亮的歌词 |
| | | Paint paintHL=new Paint(); //画笔,用于画高亮的歌词,即当前唱到这句歌词 |
| | | |
| | | public LyricView(Context context) { |
| | | super(context); |
| | | init(); |
| | | } |
| | | public LyricView(Context context, AttributeSet attr) { |
| | | super(context, attr); |
| | | |
| | | public LyricView(Context context, AttributeSet attrs) { |
| | | super(context, attrs); |
| | | init(); |
| | | } |
| | | public LyricView(Context context, AttributeSet attr, int i) { |
| | | super(context, attr, i); |
| | | init(); |
| | | } |
| | | private void init() { |
| | | setFocusable(true); |
| | | if(list==null){ |
| | | list=new ArrayList<Sentence>(); |
| | | Sentence sen=new Sentence(0," "); |
| | | list.add(0, sen); |
| | | } |
| | | // |
| | | mPaint = new Paint(); |
| | | mPaint.setAntiAlias(true); |
| | | mPaint.setTextSize(24); |
| | | mPaint.setColor(Color.BLACK); |
| | | mPaint.setAlpha(80); |
| | | mPaint.setTypeface(Typeface.SERIF); |
| | | // |
| | | mPathPaint = new Paint(); |
| | | mPathPaint.setAntiAlias(true); |
| | | mPathPaint.setColor(Color.RED); |
| | | mPathPaint.setTextSize(24); |
| | | mPathPaint.setTypeface(Typeface.SANS_SERIF); |
| | | } |
| | | |
| | | /* (non-Javadoc) |
| | | * @see android.view.View#onDraw(android.graphics.Canvas) |
| | | */ |
| | | @Override |
| | | protected void onDraw(Canvas canvas) { |
| | | if(LyricServer.getLrc_map().size() > 0){ |
| | | paintHL.setTextSize(SIZEWORD); |
| | | paint.setTextSize(SIZEWORD); |
| | | LyricObject temp= LyricServer.getLrc_map().get(lrcIndex); |
| | | canvas.drawText(temp.lrc, mX, offsetY+(SIZEWORD+INTERVAL)*lrcIndex, paintHL); |
| | | // 画当前歌词之前的歌词 |
| | | for(int i=lrcIndex-1;i>=0;i--){ |
| | | temp=LyricServer.getLrc_map().get(i); |
| | | if(offsetY+(SIZEWORD+INTERVAL)*i<0){ |
| | | break; |
| | | } |
| | | canvas.drawText(temp.lrc, mX, offsetY+(SIZEWORD+INTERVAL)*i, paint); |
| | | } |
| | | // 画当前歌词之后的歌词 |
| | | for(int i=lrcIndex+1;i<LyricServer.getLrc_map().size();i++){ |
| | | temp=LyricServer.getLrc_map().get(i); |
| | | if(offsetY+(SIZEWORD+INTERVAL)*i>600){ |
| | | break; |
| | | } |
| | | canvas.drawText(temp.lrc, mX, offsetY+(SIZEWORD+INTERVAL)*i, paint); |
| | | } |
| | | } |
| | | else{ |
| | | paint.setTextSize(25); |
| | | canvas.drawText("找不到歌词", mX, 310, paint); |
| | | } |
| | | super.onDraw(canvas); |
| | | canvas.drawColor(0xEFeffff); |
| | | Paint p = mPaint; |
| | | Paint p2 = mPathPaint; |
| | | p.setTextAlign(Paint.Align.LEFT); |
| | | if (index == -1) |
| | | return; |
| | | p2.setTextAlign(Paint.Align.LEFT); |
| | | // |
| | | canvas.drawText(list.get(index).getName(), mX, middleY, p2); |
| | | float tempY = middleY; |
| | | // |
| | | for (int i = index - 1; i >= 0; i--) { |
| | | tempY = tempY - DY; |
| | | if (tempY < 0) { |
| | | } |
| | | |
| | | /* (non-Javadoc) |
| | | * @see android.view.View#onTouchEvent(android.view.MotionEvent) |
| | | */ |
| | | @Override |
| | | public boolean onTouchEvent(MotionEvent event) { |
| | | // TODO Auto-generated method stub |
| | | float tt=event.getY(); |
| | | switch(event.getAction()){ |
| | | case MotionEvent.ACTION_DOWN: |
| | | break; |
| | | case MotionEvent.ACTION_MOVE: |
| | | touchY=tt-touchY; |
| | | offsetY=offsetY+touchY; |
| | | Log.e("LyricView","offsety:"+offsetY); |
| | | invalidate(); |
| | | break; |
| | | case MotionEvent.ACTION_UP: |
| | | break; |
| | | } |
| | | canvas.drawText(list.get(i).getName(), mX, tempY, p); |
| | | touchY=tt; |
| | | return true; |
| | | } |
| | | tempY = middleY; |
| | | // |
| | | for (int i = index + 1; i < list.size(); i++) { |
| | | // |
| | | tempY = tempY + DY; |
| | | if (tempY > mY) { |
| | | break; |
| | | |
| | | public void init(){ |
| | | offsetY=320; |
| | | |
| | | paint=new Paint(); |
| | | paint.setTextAlign(Paint.Align.CENTER); |
| | | paint.setColor(Color.GREEN); |
| | | paint.setAntiAlias(true); |
| | | paint.setDither(true); |
| | | paint.setAlpha(180); |
| | | |
| | | |
| | | paintHL=new Paint(); |
| | | paintHL.setTextAlign(Paint.Align.CENTER); |
| | | |
| | | paintHL.setColor(Color.RED); |
| | | paintHL.setAntiAlias(true); |
| | | paintHL.setAlpha(255); |
| | | } |
| | | canvas.drawText(list.get(i).getName(), mX, tempY, p); |
| | | } |
| | | } |
| | | protected void onSizeChanged(int w, int h, int ow, int oh) { |
| | | super.onSizeChanged(w, h, ow, oh); |
| | | mX = w * 0.3f; |
| | | mY = h; |
| | | middleY = h * 0.5f; |
| | | } |
| | | public long updateIndex(int index) { |
| | | if (index == -1) |
| | | return -1; |
| | | this.index=index; |
| | | return index; |
| | | } |
| | | public List<Sentence> getList() { |
| | | return list; |
| | | } |
| | | public void setList(List<Sentence> list) { |
| | | this.list = list; |
| | | } |
| | | public void updateUI(){ |
| | | new Thread(new updateThread()).start(); |
| | | } |
| | | class updateThread implements Runnable { |
| | | long time = 300; |
| | | int i=0; |
| | | public void run() { |
| | | while (true) { |
| | | long sleeptime = updateIndex(i); |
| | | time += sleeptime; |
| | | mHandler.post(mUpdateResults); |
| | | if (sleeptime == -1) |
| | | |
| | | /** |
| | | * 根据歌词里面最长的那句来确定歌词字体的大小 |
| | | */ |
| | | public void setTextSize(){ |
| | | if(LyricServer.getLrc_map().size() == 0){ |
| | | return; |
| | | try { |
| | | Thread.sleep(time); |
| | | i++; |
| | | if(i==getList().size()) |
| | | { |
| | | i=0; |
| | | time = 300; |
| | | } |
| | | } catch (InterruptedException e) { |
| | | e.printStackTrace(); |
| | | int max=LyricServer.getLrc_map().get(0).lrc.length(); |
| | | for(int i=1;i<LyricServer.getLrc_map().size();i++){ |
| | | LyricObject lrcStrLength=LyricServer.getLrc_map().get(i); |
| | | if(max<lrcStrLength.lrc.length()){ |
| | | max=lrcStrLength.lrc.length(); |
| | | } |
| | | } |
| | | SIZEWORD = DeviceUtil.convertDpToPixel(320/max,getContext()); |
| | | |
| | | } |
| | | |
| | | protected void onSizeChanged(int w, int h, int oldw, int oldh) { |
| | | mX = w * 0.5f; |
| | | super.onSizeChanged(w, h, oldw, oldh); |
| | | } |
| | | |
| | | /** |
| | | * 歌词滚动的速度 |
| | | * |
| | | * @return 返回歌词滚动的速度 |
| | | */ |
| | | public Float SpeedLrc(){ |
| | | float speed=0; |
| | | if(offsetY+(SIZEWORD+INTERVAL)*lrcIndex>220){ |
| | | speed=((offsetY+(SIZEWORD+INTERVAL)*lrcIndex-220)/20); |
| | | |
| | | } else if(offsetY+(SIZEWORD+INTERVAL)*lrcIndex < 120){ |
| | | Log.i("speed", "speed is too fast!!!"); |
| | | speed = 0; |
| | | } |
| | | // if(speed<0.2){ |
| | | // speed=0.2f; |
| | | // } |
| | | return speed; |
| | | } |
| | | |
| | | /** |
| | | * 按当前的歌曲的播放时间,从歌词里面获得那一句 |
| | | * @param time 当前歌曲的播放时间 |
| | | * @return 返回当前歌词的索引值 |
| | | */ |
| | | public int getIndex(int time){ |
| | | int index=0; |
| | | for(int i=0;i<LyricServer.getLrc_map().size();i++){ |
| | | LyricObject temp=LyricServer.getLrc_map().get(i); |
| | | if(temp.begintime<time){ |
| | | ++index; |
| | | } |
| | | } |
| | | Handler mHandler = new Handler(); |
| | | Runnable mUpdateResults = new Runnable() { |
| | | public void run() { |
| | | invalidate(); // |
| | | lrcIndex = index-1; |
| | | if(lrcIndex<0){ |
| | | lrcIndex=0; |
| | | } |
| | | }; |
| | | return lrcIndex; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * @return the offsetY |
| | | */ |
| | | public float getOffsetY() { |
| | | return offsetY; |
| | | } |
| | | |
| | | /** |
| | | * @param offsetY the offsetY to set |
| | | */ |
| | | public void setOffsetY(float offsetY) { |
| | | this.offsetY = offsetY; |
| | | } |
| | | |
| | | /** |
| | | * @return 返回歌词文字的大小 |
| | | */ |
| | | public int getSIZEWORD() { |
| | | return SIZEWORD; |
| | | } |
| | | |
| | | /** |
| | | * 设置歌词文字的大小 |
| | | * @param sIZEWORD the sIZEWORD to set |
| | | */ |
| | | public void setSIZEWORD(int sIZEWORD) { |
| | | SIZEWORD = sIZEWORD; |
| | | } |
| | | } |