We need to read each line of the lyrics file above to convert it into a lyric entity:
Copy Code code as follows:
public class Lyricobject {
public int begintime; Start time
public int endtime; End time
public int timeline; When the lyrics of a simple sentence
Public String LRC; The lyrics of simple sentences
}
According to the current player's playback progress and the start time of each line of lyrics, the current screen highlighted in the center of the sentence lyrics. In the UI thread, another thread is OnDraw () to redraw the screen every 100ms to achieve the animation effect of the lyrics smoothing scrolling. The mainactivity code is as follows:
Copy Code code as follows:
Import java.io.IOException;
Import android.app.Activity;
Import Android.media.MediaPlayer;
Import Android.net.Uri;
Import Android.os.Bundle;
Import android.os.Environment;
Import Android.os.Handler;
Import Android.view.View;
Import Android.view.View.OnClickListener;
Import Android.widget.Button;
Import Android.widget.SeekBar;
Import Android.widget.SeekBar.OnSeekBarChangeListener;
public class Mainactivity extends activity {
/** called the activity is a. */
Private Lyricview Lyricview;
Private MediaPlayer MediaPlayer;
Private button button;
Private SeekBar SeekBar;
Private String Mp3path;
private int interval=45;//lyrics each line spacing
@Override
public void OnCreate (Bundle savedinstancestate) {
Super.oncreate (savedinstancestate);
This.requestwindowfeature (Window.feature_no_title);
GetWindow (). SetFlags (WindowManager.LayoutParams.FLAG_FULLSCREEN);
Setcontentview (R.layout.main);
Mp3path = Environment.getexternalstoragedirectory (). GetAbsolutePath () + "/lyricsync/1.mp3";
Lyricview = (Lyricview) Findviewbyid (R.ID.MYLRC);
MediaPlayer = new MediaPlayer ();
This.requestwindowfeature (Window.feature_no_title);
Resetmusic (Mp3path);
SERCHLRC ();
Lyricview.settextsize ();
Button = (button) Findviewbyid (R.id.button);
Button.settext ("Play");
SeekBar = (SeekBar) Findviewbyid (r.id.seekbarmusic);
Seekbar.setonseekbarchangelistener (New Onseekbarchangelistener () {
@Override
public void Onstoptrackingtouch (SeekBar SeekBar) {
TODO auto-generated Method Stub
}
@Override
public void Onstarttrackingtouch (SeekBar SeekBar) {
TODO auto-generated Method Stub
}
@Override
public void onprogresschanged (SeekBar SeekBar, int progress,
Boolean Fromuser) {
TODO auto-generated Method Stub
if (Fromuser) {
Mediaplayer.seekto (progress);
Lyricview.setoffsety (220-lyricview.selectindex (Progress)
* (Lyricview.getsizeword () + INTERVAL-1));
}
}
});
Button.setonclicklistener (New Onclicklistener () {
@Override
public void OnClick (View v) {
TODO auto-generated Method Stub
if (mediaplayer.isplaying ()) {
Button.settext ("Play");
Mediaplayer.pause ();
} else {
Button.settext ("suspend");
Mediaplayer.start ();
Lyricview.setoffsety (220-lyricview.selectindex (Mediaplayer.getcurrentposition ())
* (Lyricview.getsizeword () + INTERVAL-1));
}
}
});
Mediaplayer.setoncompletionlistener (New Mediaplayer.oncompletionlistener () {
@Override
public void Oncompletion (MediaPlayer MP) {
Resetmusic (Mp3path);
Lyricview.settextsize ();
Lyricview.setoffsety (200);
Mediaplayer.start ();
}
});
Seekbar.setmax (Mediaplayer.getduration ());
New Thread (New Runable ()). Start ();
}
public void Serchlrc () {
String LRC = Mp3path;
LRC = lrc.substring (0, Lrc.length ()-4). Trim () + ". LRC". Trim ();
Lyricview.read (LRC);
Lyricview.settextsize ();
Lyricview.setoffsety (350);
}
public void Resetmusic (String path) {
Mediaplayer.reset ();
try {
Mediaplayer.setdatasource (Mp3path);
Mediaplayer.prepare ();
catch (IllegalArgumentException e) {
TODO auto-generated Catch block
E.printstacktrace ();
catch (IllegalStateException e) {
TODO auto-generated Catch block
E.printstacktrace ();
catch (IOException e) {
TODO auto-generated Catch block
E.printstacktrace ();
}
}
Class Runable implements Runnable {
@Override
public void Run () {
TODO auto-generated Method Stub
while (true) {
try {
Thread.Sleep (100);
if (mediaplayer.isplaying ()) {
Lyricview.setoffsety (Lyricview.getoffsety ()-LYRICVIEW.SPEEDLRC ());
Lyricview.selectindex (Mediaplayer.getcurrentposition ());
Seekbar.setprogress (Mediaplayer.getcurrentposition ());
Mhandler.post (Mupdateresults);
}
catch (Interruptedexception e) {
TODO auto-generated Catch block
E.printstacktrace ();
}
}
}
}
Handler Mhandler = new Handler ();
Runnable mupdateresults = new Runnable () {
public void Run () {
Lyricview.invalidate (); Update view
}
};
}
The code for the lyrics view is as follows:
Copy Code code as follows:
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.TreeMap;
Import Java.util.regex.Matcher;
Import Java.util.regex.Pattern;
Import Android.content.Context;
Import Android.graphics.Canvas;
Import Android.graphics.Color;
Import Android.graphics.Paint;
Import Android.util.AttributeSet;
Import Android.util.Log;
Import android.view.MotionEvent;
Import Android.view.View;
public class Lyricview extends view{
private static Treemap<integer, lyricobject> Lrc_map;
private float MX; The midpoint of the x-axis of the screen, fixed with this value, to keep the lyrics displayed in the middle of X
private float OffsetY; The offset of the lyrics on the y-axis, which is smaller by the scroll of the lyrics
private static Boolean bllrc=false;
private float touchy; When you touch the lyrics view, save as the y-coordinate of the current contact.
private float Touchx;
Private Boolean blscrollview=false;
private int lrcindex=0; Save Lyrics TreeMap Subscript
private int sizeword=0;//Display the size value of the lyrics text
private int interval=45;//lyrics each line spacing
Paint paint=new Paint ()//brush, for painting not highlighted lyrics
Paint painthl=new Paint (); A brush used to paint the lyrics of a highlight, that is, the lyrics that are currently sung
Public Lyricview {
Super (context);
Init ();
}
Public Lyricview (context context, AttributeSet Attrs) {
Super (context, attrs);
Init ();
}
/* (Non-javadoc)
* @see Android.view.view#ondraw (Android.graphics.Canvas)
*/
@Override
protected void OnDraw (Canvas Canvas) {
if (BLLRC) {
Painthl.settextsize (Sizeword);
Paint.settextsize (Sizeword);
Lyricobject Temp=lrc_map.get (Lrcindex);
Canvas.drawtext (TEMP.LRC, MX, offsety+ (sizeword+interval) *lrcindex, PAINTHL);
Draw lyrics before the current lyrics
for (int i=lrcindex-1;i>=0;i--) {
Temp=lrc_map.get (i);
if (offsety+ (sizeword+interval) *i<0) {
Break
}
Canvas.drawtext (TEMP.LRC, MX, offsety+ (sizeword+interval) *i, paint);
}
Draw lyrics after the current lyrics
for (int i=lrcindex+1;i<lrc_map.size (); i++) {
Temp=lrc_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 ("Lyrics not Found", MX, 310, paint);
}
Super.ondraw (canvas);
}
/* (Non-javadoc)
* @see android.view.view#ontouchevent (android.view.MotionEvent)
*/
@Override
public boolean ontouchevent (Motionevent event) {
TODO auto-generated Method Stub
System.out.println ("bllll===" +blscrollview);
float tt=event.gety ();
if (!BLLRC) {
Return Super.ontouchevent (event);
Return Super.ontouchevent (event);
}
Switch (event.getaction ()) {
Case Motionevent.action_down:
Touchx=event.getx ();
Break
Case Motionevent.action_move:
Touchy=tt-touchy;
Offsety=offsety+touchy;
Break
Case MOTIONEVENT.ACTION_UP:
Blscrollview=false;
Break
}
Touchy=tt;
return true;
}
public void init () {
Lrc_map = new Treemap<integer, lyricobject> ();
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);
}
/**
* According to the longest sentence in the lyrics to determine the size of the lyrics font
*/
public void Settextsize () {
if (!BLLRC) {
Return
}
int Max=lrc_map.get (0). Lrc.length ();
for (int i=1;i<lrc_map.size (); i++) {
Lyricobject Lrcstrlength=lrc_map.get (i);
if (Max<lrcstrlength.lrc.length ()) {
Max=lrcstrlength.lrc.length ();
}
}
Sizeword=320/max;
}
protected void onsizechanged (int w, int h, int oldw, int oldh) {
MX = w * 0.5f;
Super.onsizechanged (W, H, OLDW, OLDH);
}
/**
* The speed of the lyrics rolling
*
* @return return the speed of the lyrics scrolling
*/
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;
}
/**
* According to the current song play Time, from the lyrics to get that sentence
* @param time to play the current song
* @return Returns the index value of the current lyrics
*/
public int Selectindex (int time) {
if (!BLLRC) {
return 0;
}
int index=0;
for (int i=0;i<lrc_map.size (); i++) {
Lyricobject Temp=lrc_map.get (i);
if (temp.begintime<time) {
++index;
}
}
Lrcindex=index-1;
if (lrcindex<0) {
lrcindex=0;
}
return lrcindex;
}
/**
* Read Lyrics file
* @param the path of the file lyrics
*
*/
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 ("Whether there is a lyric file" +savefile.isfile ());
if (!savefile.isfile ()) {
Bllrc=false;
Return
}
Bllrc=true;
System.out.println ("bllrc===" +BLLRC);
FileInputStream stream = new FileInputStream (savefile);//Context.openfileinput (file);
BufferedReader br = new BufferedReader (new InputStreamReader (Stream, "GB2312"));
int i = 0;
Pattern pattern = Pattern.compile ("\\d{2}");
while (data = Br.readline ())!= null) {
System.out.println ("++++++++++++>>" +data);
data = Data.replace ("[", "");//Replace the front with the back
data = Data.replace ("]", "@");
String splitdata[] =data.split ("@");//Delimited
if (Data.endswith ("@")) {
for (int k=0;k<splitdata.length;k++) {
String Str=splitdata[k];
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]); Part
int s = integer.parseint (timedata[1]); Seconds
int ms = Integer.parseint (timedata[2]); Milliseconds
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[splitdata.length-1];
for (int j=0;j<splitdata.length-1;j++)
{
String tmpstr = Splitdata[j];
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]); Part
int s = integer.parseint (timedata[1]); Seconds
int ms = Integer.parseint (timedata[2]); Milliseconds
int currtime = (m*60+s) *1000+ms*10;
Lyricobject item1= new Lyricobject ();
Item1.begintime = Currtime;
ITEM1.LRC = lrccontenet;
Lrc_read.put (CURRTIME,ITEM1)//Will currtime as label item1 when data is inserted into TreeMap
i++;
}
}
}
}
Stream.Close ();
}
catch (FileNotFoundException e) {
}
catch (IOException e) {
}
/*
* Traverse HashMap to calculate the time required for each line of lyrics
*/
Lrc_map.clear ();
data = "";
Iterator<integer> iterator = Lrc_read.keyset (). iterator ();
Lyricobject oldval = null;
int i = 0;
while (Iterator.hasnext ()) {
Object ob =iterator.next ();
Lyricobject val = (lyricobject) lrc_read.get (OB);
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 (!iterator.hasnext ()) {
Lrc_map.put (New Integer (i), Val);
}
}
}
/**
* @return The BLLRC
*/
public static Boolean ISBLLRC () {
return BLLRC;
}
/**
* @return The OffsetY
*/
public float getoffsety () {
return OffsetY;
}
/**
* @param offsetY the OffsetY to set
*/
public void setoffsety (float OffsetY) {
This.offsety = OffsetY;
}
/**
* @return Return the size of the lyric text
*/
public int Getsizeword () {
return Sizeword;
}
/**
* Set the size of the lyric text
* @param sizeword the Sizeword to set
*/
public void Setsizeword (int sizeword) {
Sizeword = Sizeword;
}
}
The XML layout file is as follows:
Copy Code code as follows:
<span style= "font-size:18px" ><strong><?xml version= "1.0" encoding= "Utf-8"?>
<relativelayout xmlns:android= "Http://schemas.android.com/apk/res/android"
Android:layout_width= "Fill_parent"
android:layout_height= "Fill_parent"
android:background= "#FFFFFF" >
<com.music.lyricsync.lyricview
Android:id= "@+id/mylrc"
Android:layout_width= "Fill_parent"
android:layout_height= "Fill_parent"
Android:layout_marginbottom= "50dip"
android:layout_margintop= "50dip"/>
<linearlayout
Xmlns:android= "Http://schemas.android.com/apk/res/android"
Android:layout_width= "Wrap_content"
android:layout_height= "Wrap_content"
Android:layout_alignparentbottom= "true"
android:orientation= "Horizontal" >
<button
Android:id= "@+id/button"
Android:layout_width= "Wrap_content"
android:layout_height= "Wrap_content"/>
<seekbar
Android:id= "@+id/seekbarmusic"
Android:layout_width= "205px"
android:layout_height= "Wrap_content"
Android:layout_gravity= "Center_vertical"
Android:layout_marginbottom= "5px"
android:progress= "0"/>
</LinearLayout>
</RelativeLayout> </STRONG></SPAN>