app/src/main/java/com/auto/lyric/MainActivity.java
@@ -1,27 +1,26 @@ package com.auto.lyric; import android.content.Intent; import android.graphics.PixelFormat; import android.net.Uri; import android.os.Build; import android.os.Handler; import android.os.Message; import android.provider.Settings; import android.text.TextUtils; import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.WindowManager; import androidx.annotation.NonNull; import android.widget.Toast; import com.auto.lyric.base.activities.BaseActivity; import com.auto.lyric.data.LyricServer; import com.auto.lyric.data.TextBean; import com.auto.lyric.databinding.ActivityMainBinding; import com.auto.lyric.databinding.FloatViewBinding; import com.auto.lyric.service.AutoInputService; import com.auto.lyric.service.FloatingWindowService; import com.auto.lyric.vm.MainViewModel; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.regex.Pattern; public class MainActivity extends BaseActivity<ActivityMainBinding, MainViewModel> { @@ -33,10 +32,38 @@ Intent floatService = new Intent(getApplicationContext(), FloatingWindowService.class); binding.button.setOnClickListener(v -> { if(binding.edit.getText().toString().trim().length() == 0){ Toast.makeText(this,"请输入文本", Toast.LENGTH_SHORT).show(); return; } ArrayList<TextBean> arrayList = new ArrayList<>();//解析的文本数据 SimpleDateFormat msFormat = new SimpleDateFormat("mm:ss.SSS"); String[] strings = binding.edit.getText().toString().split("\n"); for(String text : strings){ int index = text.indexOf("]"); if(index < 8 ){ continue; } String regex = "(?<=\\])"; Pattern compile = Pattern.compile(regex); String[] split = compile.split(text,2); long wait = 0; try { wait = 28800000 + msFormat.parse(split[0].replace("[","").replace("]","")).getTime(); } catch (ParseException e) { e.printStackTrace(); } arrayList.add(new TextBean(wait,split[1])); } if(arrayList.size() == 0){ return; } LyricServer.read(Arrays.asList(strings)); //申请权限 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { //开启悬浮窗 /* if(!Settings.canDrawOverlays(getApplicationContext())) { if(!Settings.canDrawOverlays(getApplicationContext())) { //启动Activity让用户授权 Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION); intent.setData(Uri.parse("package:" + getPackageName())); @@ -47,10 +74,8 @@ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK ); startActivity(intent); }else{//开启监听服务 //startService(floatService); }*/ startService(floatService); //showFloatView(); } } }); } @@ -93,27 +118,5 @@ return false; } private void showFloatView(){ //View view = LayoutInflater.from(this).inflate(R.layout.float_view,null); FloatViewBinding binding = FloatViewBinding.inflate(getLayoutInflater()); WindowManager manager = (WindowManager) getApplicationContext().getSystemService(WINDOW_SERVICE); WindowManager.LayoutParams params = new WindowManager.LayoutParams(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; }else { params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; } params.format = PixelFormat.RGBA_8888; params.gravity = Gravity.CENTER; params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; params.width = WindowManager.LayoutParams.MATCH_PARENT; params.height = WindowManager.LayoutParams.WRAP_CONTENT; binding.btnBack.setOnClickListener(v ->{ stopService(new Intent(this,this.getClass())); }); manager.addView(binding.getRoot(),params); } } app/src/main/java/com/auto/lyric/base/activities/BaseActivity.java
@@ -243,19 +243,6 @@ InputMethodManager.HIDE_NOT_ALWAYS); } } /** * 状态栏高度 * @return */ public int getStatusBarHeight() { int result = 0; int resId = getResources().getIdentifier("status_bar_height", "dimen", "android"); if (resId > 0) { result = getResources().getDimensionPixelOffset(resId); } return result; } long mExitTime= 0 ; /** app/src/main/java/com/auto/lyric/base/activities/BaseTitleBarActivity.java
@@ -8,6 +8,7 @@ import androidx.viewbinding.ViewBinding; import com.auto.lyric.base.model.BaseViewModel; import com.auto.lyric.util.DeviceUtil; import com.auto.lyric.widgets.TitleBarView; @@ -54,7 +55,7 @@ public void setStatusBarTransparent(boolean isBlack) { super.setStatusBarTransparent(isBlack); final ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) titleBarView.getLayoutParams(); layoutParams.topMargin = layoutParams.topMargin+getStatusBarHeight(); layoutParams.topMargin = layoutParams.topMargin+ DeviceUtil.getStatusBarHeight(this); titleBarView.setLayoutParams(layoutParams); } app/src/main/java/com/auto/lyric/data/LyricObject.java
New file @@ -0,0 +1,11 @@ package com.auto.lyric.data; /** * Created by Runt (qingingrunt2010@qq.com) on 2022/5/2. */ public class LyricObject { public int begintime; // 开始时间 public int endtime; // 结束时间 public int timeline; // 单句歌词用时 public String lrc; // 单句歌词 } app/src/main/java/com/auto/lyric/data/LyricServer.java
New file @@ -0,0 +1,143 @@ package com.auto.lyric.data; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.util.Iterator; import java.util.List; import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Created by Runt (qingingrunt2010@qq.com) on 2022/5/4. */ public class LyricServer { private static TreeMap<Integer, LyricObject> lrc_map = new TreeMap<>(); public static TreeMap<Integer, LyricObject> getLrc_map() { return lrc_map; } /** * 读取歌词文件 * @param file 歌词的路径 * */ public static void read(String file) { TreeMap<Integer, LyricObject> lrc_read =new TreeMap<Integer, LyricObject>(); String data = ""; try { File saveFile=new File(file); // System.out.println("是否有歌词文件"+saveFile.isFile()); if(!saveFile.isFile()){ return; } //System.out.println("bllrc==="+blLrc); FileInputStream stream = new FileInputStream(saveFile);// context.openFileInput(file); BufferedReader br = new BufferedReader(new InputStreamReader(stream,"GB2312")); while ((data = br.readLine()) != null) { readText(data,lrc_read); } stream.close(); } catch (FileNotFoundException e) { } catch (IOException e) { } data =""; initLrc(lrc_read); } public static void read(List<String> texts){ TreeMap<Integer, LyricObject> lrc_read =new TreeMap<Integer, LyricObject>(); for(String str : texts){ readText(str,lrc_read); } initLrc(lrc_read); } private static void readText(String text,TreeMap<Integer, LyricObject> lrc_read){ Pattern pattern = Pattern.compile("\\d{2}"); // System.out.println("++++++++++++>>"+data); /*text = text.replace("[","");//将前面的替换成后面的 text = text.replace("]","@"); String splitdata[] = text.split("@");//分隔*/ String regex = "(?<=\\])"; Pattern compile = Pattern.compile(regex); String[] splitdata = compile.split(text,2);//分隔 if(text.endsWith("]") || splitdata.length == 1){ String str = text; str = str.replace("[",""); str = str.replace("]",""); str = str.replace(":","."); str = str.replace(".","@"); String timedata[] =str.split("@"); Matcher matcher = pattern.matcher(timedata[0]); if(timedata.length==3 && matcher.matches()){ int m = Integer.parseInt(timedata[0]); //分 int s = Integer.parseInt(timedata[1]); //秒 int ms = Integer.parseInt(timedata[2]); //毫秒 int currTime = (m*60+s)*1000+ms*10; LyricObject item1= new LyricObject(); item1.begintime = currTime; item1.lrc = ""; lrc_read.put(currTime,item1); } } else{ String lrcContenet = splitdata[1]; String tmpstr = splitdata[0]; tmpstr = tmpstr.replace("[",""); tmpstr = tmpstr.replace("]",""); tmpstr = tmpstr.replace(":","."); tmpstr = tmpstr.replace(".","@"); String timedata[] =tmpstr.split("@"); Matcher matcher = pattern.matcher(timedata[0]); if(timedata.length==3 && matcher.matches()){ int m = Integer.parseInt(timedata[0]); //分 int s = Integer.parseInt(timedata[1]); //秒 int ms = Integer.parseInt(timedata[2]); //毫秒 int currTime = (m*60+s)*1000+ms*10; LyricObject item1= new LyricObject(); item1.begintime = currTime; item1.lrc = lrcContenet; lrc_read.put(currTime,item1);// 将currTime当标签 item1当数据 插入TreeMap里 } } } /* * 遍历hashmap 计算每句歌词所需要的时间 */ private static void initLrc(TreeMap<Integer, LyricObject> lrc_read){ lrc_map.clear(); Iterator<Integer> iterator = lrc_read.keySet().iterator(); LyricObject oldval = null; int i =0; for(Integer key : lrc_read.keySet()){ LyricObject val = lrc_read.get(key); if (oldval == null) { oldval = val; } else { LyricObject item1= new LyricObject(); item1 = oldval; item1.timeline = val.begintime-oldval.begintime; lrc_map.put(new Integer(i), item1); i++; oldval = val; } if (lrc_read.size() > i) { lrc_map.put(new Integer(i), val); } } } } app/src/main/java/com/auto/lyric/data/SendText.java
New file @@ -0,0 +1,14 @@ package com.auto.lyric.data; import java.util.ArrayList; /** * Created by Runt (qingingrunt2010@qq.com) on 2022/5/1. */ public class SendText { public ArrayList<String> texts;//文本 public SendText(ArrayList<String> texts) { this.texts = texts; } } app/src/main/java/com/auto/lyric/data/TextBean.java
New file @@ -0,0 +1,14 @@ package com.auto.lyric.data; /** * Created by Runt (qingingrunt2010@qq.com) on 2022/5/1. */ public class TextBean { public TextBean(long waitTime, String text) { this.waitTime = waitTime; this.text = text; } public long waitTime;//间隔时间 public String text;//文本 } app/src/main/java/com/auto/lyric/service/FloatingWindowService.java
@@ -1,6 +1,9 @@ package com.auto.lyric.service; import android.app.Service; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; import android.content.Intent; import android.graphics.PixelFormat; import android.os.Build; @@ -13,14 +16,21 @@ import android.view.MotionEvent; import android.view.View; import android.view.WindowManager; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.view.LayoutInflaterFactory; import com.auto.lyric.R; import com.auto.lyric.data.LyricServer; import com.auto.lyric.databinding.FloatViewBinding; import com.auto.lyric.util.DeviceUtil; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Timer; import java.util.TimerTask; /** * 全局悬浮窗 @@ -31,9 +41,29 @@ private WindowManager manager; private WindowManager.LayoutParams params; FloatViewBinding binding; Handler handler; final String TAG = "FloatingWindowService"; final int THREAD_STOP = 0, THREAD_START = 1 , KEYBOARD_SEND = 100,UPDATE_TIME = 200; SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); SimpleDateFormat msFormat = new SimpleDateFormat("mm:ss.SSS"); boolean pause; int progress; Handler handler; Timer timer; ServiceTask task; class ServiceTask extends TimerTask{ @Override public void run() { int index = binding.lyric.getIndex(progress+=10); binding.lyric.setOffsetY(220 - index * (binding.lyric.getSIZEWORD() + 44)); binding.lyric.invalidate(); handler.sendEmptyMessage(UPDATE_TIME); if(index == LyricServer.getLrc_map().size()-1){ handler.sendEmptyMessage(THREAD_STOP); } } }; @Override public void onCreate() { super.onCreate(); @@ -47,19 +77,14 @@ }else { params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; } binding.btnBack.setEnabled(false); binding.btnFast.setEnabled(false); binding.btnPause.setEnabled(false); params.format = PixelFormat.RGBA_8888; params.gravity = Gravity.LEFT | Gravity.TOP; params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; params.width = WindowManager.LayoutParams.MATCH_PARENT; params.height = DeviceUtil.convertDpToPixel(200,getBaseContext()); handler = new Handler(this.getMainLooper()){ @Override public void handleMessage(@NonNull Message msg) { binding.lyric.setText(msg.obj.toString()); int offset = binding.lyric.getLineCount() * binding.lyric.getLineHeight(); } }; binding.close.setOnClickListener(v ->{ stopService(new Intent(this,this.getClass())); stopService(new Intent(this,AutoInputService.class)); @@ -75,14 +100,58 @@ || event.getAction() == MotionEvent.ACTION_UP){ params.y = (int) event.getRawY() - DeviceUtil.getStatusBarHeight(getBaseContext()) - startY; manager.updateViewLayout(binding.getRoot(), params); Log.e(TAG,"ACTION_MOVE V:"+params.y); //Log.e(TAG,"ACTION_MOVE V:"+params.y); } Log.e(TAG,"onTouch event:"+event); Log.e(TAG,"onTouch getRawY:"+event.getRawY()); // Log.e(TAG,"onTouch event:"+event); // Log.e(TAG,"onTouch getRawY:"+event.getRawY()); return true; } }); binding.btnPause.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if(pause){ pause = false; binding.btnPause.setText("暂停"); binding.btnBack.setEnabled(true); binding.btnFast.setEnabled(true); start(); }else{ pause = true; binding.btnPause.setText("继续"); binding.btnBack.setEnabled(false); binding.btnFast.setEnabled(false); timer.cancel(); } } }); binding.btnFast.setOnClickListener(v -> progress+=700); binding.btnBack.setOnClickListener(v -> progress-=700); binding.btnStart.setOnClickListener(v -> { try { if(new Date().getTime() > dateFormat.parse("2022-09-30 04:00:00").getTime()){ Toast.makeText(getApplicationContext(),"软件使用时间已过期", Toast.LENGTH_SHORT).show(); return; } } catch (ParseException e) { e.printStackTrace(); } if(binding.btnStart.getText().equals("开启")){ progress = 0 ; start(); startService(new Intent(this,AutoInputService.class)); }else{ binding.btnStart.setText("开启"); binding.btnBack.setEnabled(false); binding.btnFast.setEnabled(false); binding.btnPause.setEnabled(false); progress = 0 ; timer.cancel(); stopService(new Intent(this,AutoInputService.class)); } }); initHandler(); } @Nullable @@ -91,10 +160,41 @@ return null; } private void initHandler(){ handler = new Handler(this.getMainLooper()){ @Override public void handleMessage(@NonNull Message msg) { super.handleMessage(msg); if(msg.what == THREAD_START){//开始 AutoInputService.flag = true; binding.btnPause.performClick(); }else if(msg.what == THREAD_STOP){//停止 AutoInputService.flag = false; binding.btnStart.performClick(); }else if(msg.what == KEYBOARD_SEND){//发送文本 copy(msg.obj.toString()); Intent intent = new Intent(); intent.setAction(AutoInputService.class.getName()); intent.putExtra("action",AutoInputService.ACTION_PASTE); sendBroadcast(intent); intent.putExtra("action",AutoInputService.ACTION_SEND); sendBroadcast(intent); }else if(msg.what == -1){//显示在输入框中 //Toast.makeText(getBaseContext(),"上一句--"+msg.obj,Toast.LENGTH_SHORT).show(); }else if(msg.what == UPDATE_TIME){ binding.timer.setText(msFormat.format(progress)); } } }; } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.e(TAG,"onStartCommand flags:"+flags+" startId:"+startId+ " intent:"+intent); manager.addView(binding.getRoot(),params); binding.lyric.setTextSize(); return super.onStartCommand(intent, flags, startId); } @@ -102,7 +202,35 @@ public void onDestroy() { super.onDestroy(); Log.e(TAG,"onDestroy "); timer.cancel(); manager.removeView(binding.getRoot()); } /** * 开始 */ private void start(){ timer = new Timer(); task = new ServiceTask(); timer.schedule(task,0,10); binding.btnStart.setText("停止"); binding.btnPause.setText("暂停"); binding.btnBack.setEnabled(true); binding.btnFast.setEnabled(true); binding.btnPause.setEnabled(true); } //复制 private void copy(String data) { // 获取系统剪贴板 ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); // 创建一个剪贴数据集,包含一个普通文本数据条目(需要复制的数据),其他的还有 ClipData clipData = ClipData.newPlainText(null, data); // 把数据集设置(复制)到剪贴板 clipboard.setPrimaryClip(clipData); } } app/src/main/java/com/auto/lyric/widgets/LyricView.java
@@ -1,151 +1,209 @@ 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; } } app/src/main/java/com/auto/lyric/widgets/Sentence.java
@@ -6,19 +6,24 @@ public class Sentence { private String name; private int index; public Sentence(int index,String name){ this.name=name; this.index=index; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getIndex() { return index; } public void setIndex(int index) { this.index = index; } app/src/main/res/layout/activity_main.xml
@@ -16,6 +16,7 @@ android:padding="10dp" android:gravity="left" android:scrollbars="vertical" android:textCursorDrawable="@null" app:layout_constraintTop_toTopOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintLeft_toLeftOf="parent" /> app/src/main/res/layout/float_view.xml
@@ -64,5 +64,28 @@ android:textColor="@color/black" app:layout_constraintTop_toBottomOf="@id/lyric" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toRightOf="@id/btn_pause" app:layout_constraintRight_toLeftOf="@id/btn_start" /> <Button android:id="@+id/btn_start" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="开启" android:textColor="@color/black" app:layout_constraintTop_toBottomOf="@id/lyric" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintRight_toRightOf="parent"/> <TextView android:id="@+id/timer" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@color/white" android:text="0.000" android:textSize="15sp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" android:layout_marginTop="10dp" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout> app/src/main/res/values/themes.xml
@@ -2,12 +2,12 @@ <!-- Base application theme. --> <style name="Theme.AutoLyric" parent="Theme.MaterialComponents.DayNight.DarkActionBar"> <!-- Primary brand color. --> <item name="colorPrimary">@color/white</item> <item name="colorPrimaryVariant">@color/color_gray</item> <item name="colorOnPrimary">@color/white</item> <item name="colorPrimary">@color/black</item> <item name="colorPrimaryVariant">@color/gray_normal</item> <item name="colorOnPrimary">@color/gray_pressed</item> <!-- Secondary brand color. --> <item name="colorSecondary">@color/white</item> <item name="colorSecondaryVariant">@color/color_gray</item> <item name="colorSecondary">@color/gray_normal</item> <item name="colorSecondaryVariant">@color/gray_pressed</item> <item name="colorOnSecondary">@color/black</item> <!-- Status bar color. --> <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>