先看看效果图吧,再看代码
转换文件的编码格式
1 package com.xm; 2 3 import java.io.BufferedInputStream; 4 import java.io.BufferedReader; 5 import java.io.File; 6 import java.io.FileInputStream; 7 import java.io.IOException; 8 import java.io.InputStreamReader; 9 10 /** 11 * 转换文件的编码格式 12 * 13 * @author yangchuxi 14 * 15 */ 16 public class ConvertFileCode { 17 public String converfile(String filepath) { 18 File file = new File(filepath); 19 FileInputStream fis = null; 20 BufferedInputStream bis = null; 21 BufferedReader reader = null; 22 String text = ""; 23 try { 24 fis = new FileInputStream(file); 25 bis = new BufferedInputStream(fis); 26 bis.mark(4); 27 byte[] first3bytes = new byte[3]; 28 // System.out.println(""); 29 // 找到文档的前三个字节并自动判断文档类型。 30 bis.read(first3bytes); 31 bis.reset(); 32 if (first3bytes[0] == (byte) 0xEF && first3bytes[1] == (byte) 0xBB && first3bytes[2] == (byte) 0xBF) {// utf-8 33 34 reader = new BufferedReader(new InputStreamReader(bis, "utf-8")); 35 36 } else if (first3bytes[0] == (byte) 0xFF && first3bytes[1] == (byte) 0xFE) { 37 38 reader = new BufferedReader(new InputStreamReader(bis, "unicode")); 39 } else if (first3bytes[0] == (byte) 0xFE && first3bytes[1] == (byte) 0xFF) { 40 41 reader = new BufferedReader(new InputStreamReader(bis, "utf-16be")); 42 } else if (first3bytes[0] == (byte) 0xFF && first3bytes[1] == (byte) 0xFF) { 43 44 reader = new BufferedReader(new InputStreamReader(bis, "utf-16le")); 45 } else { 46 47 reader = new BufferedReader(new InputStreamReader(bis, "GBK")); 48 } 49 String str = reader.readLine(); 50 51 while (str != null) { 52 // text = text + str + "/n"; 53 // str = reader.readLine(); 54 text = text + str + "/n"; 55 str = reader.readLine(); 56 if(str==null){ 57 break; 58 } 59 System.out.println(str); 60 } 61 } catch (Exception e) { 62 e.printStackTrace(); 63 } finally { 64 if (fis != null) { 65 try { 66 fis.close(); 67 } catch (IOException e) { 68 e.printStackTrace(); 69 } 70 } 71 if (bis != null) { 72 try { 73 bis.close(); 74 } catch (IOException e) { 75 e.printStackTrace(); 76 } 77 } 78 } 79 return text; 80 } 81 }
读取歌词文件
1 package com.xm; 2 /** 3 * 读取歌词文件 4 */ 5 import java.util.ArrayList; 6 import java.util.List; 7 import java.util.regex.Matcher; 8 import java.util.regex.Pattern; 9 10 public class LrcHandle { 11 @SuppressWarnings("unchecked") 12 private List mWords = new ArrayList(); 13 14 @SuppressWarnings("unchecked") 15 private List mTimeList = new ArrayList(); 16 17 18 //处理歌词文件 19 @SuppressWarnings("unchecked") 20 public void readLRC(String path) { 21 ConvertFileCode c=new ConvertFileCode(); 22 String a =c.converfile(path); 23 String[] lists = a.split("\s"+" "+"|/n"); 24 if(mWords!=null){ 25 for(String s:lists){ 26 addTimeToList(s); 27 if ((s.indexOf("[ar:") != -1) || (s.indexOf("[ti:") != -1) 28 || (s.indexOf("[by:") != -1 || (s.indexOf("[offset:") != -1))) { 29 continue; 30 } else { 31 String ss = s.substring(s.indexOf("["), s.indexOf("]") + 1); 32 s = s.replace(ss, ""); 33 } 34 mWords.add(s); 35 } 36 }else{ 37 mWords.add("没有读取到歌词"); 38 } 39 40 41 // ConvertFileCode c=new ConvertFileCode(); 42 // String a=c.converfile("/sdcard/xn.lrc"); 43 // File file = new File(path); 44 // try { 45 // FileInputStream fileInputStream = new FileInputStream(file); 46 // InputStreamReader inputStreamReader = new InputStreamReader( 47 // fileInputStream); 48 // BufferedReader bufferedReader = new BufferedReader( 49 // inputStreamReader); 50 // String s = ""; 51 // while ((s = bufferedReader.readLine()) != null) { 52 // addTimeToList(s); 53 // if ((s.indexOf("[ar:") != -1) || (s.indexOf("[ti:") != -1) 54 // || (s.indexOf("[by:") != -1)) { 55 // s = s.substring(s.indexOf(":") + 1, s.indexOf("]")); 56 // } else { 57 // String ss = s.substring(s.indexOf("["), s.indexOf("]") + 1); 58 // s = s.replace(ss, ""); 59 // } 60 // mWords.add(s); 61 // } 62 // bufferedReader.close(); 63 // inputStreamReader.close(); 64 // fileInputStream.close(); 65 // } catch (FileNotFoundException e) { 66 // e.printStackTrace(); 67 // mWords.add("没有歌词,快去下载"); 68 // } catch (IOException e) { 69 // e.printStackTrace(); 70 // mWords.add("没有读取到歌词"); 71 // } 72 } 73 @SuppressWarnings("unchecked") 74 public List getWords() { 75 return mWords; 76 } 77 78 @SuppressWarnings("unchecked") 79 public List getTime() { 80 return mTimeList; 81 } 82 83 // 分离出时间 84 private int timeHandler(String string) { 85 string = string.replace(".", ":"); 86 String timeData[] = string.split(":"); 87 // 分离出分、秒并转换为整型 88 int minute = Integer.parseInt(timeData[0]); 89 int second = Integer.parseInt(timeData[1]); 90 int millisecond = Integer.parseInt(timeData[2]); 91 // 计算上一行与下一行的时间转换为毫秒数 92 int currentTime = (minute * 60 + second) * 1000 + millisecond * 10; 93 return currentTime; 94 } 95 96 @SuppressWarnings({ "unchecked", "unused" }) 97 private void addTimeToList(String string) { 98 Matcher matcher = Pattern.compile( 99 "\[\d{1,2}:\d{1,2}([\.:]\d{1,2})?\]").matcher(string); 100 if (matcher.find()) { 101 String str = matcher.group(); 102 mTimeList.add(new LrcHandle().timeHandler(str.substring(1, 103 str.length() - 1))); 104 } 105 } 106 }
实现xml
1 package com.xm; 2 3 import java.io.IOException; 4 import java.util.ArrayList; 5 import java.util.List; 6 7 import android.content.Context; 8 import android.graphics.Canvas; 9 import android.graphics.Color; 10 import android.graphics.Paint; 11 import android.graphics.Typeface; 12 import android.util.AttributeSet; 13 import android.widget.TextView; 14 15 public class WordView extends TextView { 16 @SuppressWarnings("unchecked") 17 private List mWordsList = new ArrayList(); 18 private Paint mLoseFocusPaint; 19 private Paint mOnFocusePaint; 20 private float mX = 0; 21 private float mMiddleY = 0; 22 private float mY = 0; 23 private static final int DY = 50; 24 private int mIndex = 0; 25 private String name; 26 27 public WordView(Context context) throws IOException { 28 super(context); 29 init(); 30 } 31 32 public WordView(Context context, AttributeSet attrs) throws IOException { 33 super(context, attrs); 34 init(); 35 } 36 37 public WordView(Context context, AttributeSet attrs, int defStyle)throws IOException { 38 super(context, attrs, defStyle); 39 init(); 40 } 41 42 @Override 43 protected void onDraw(Canvas canvas) { 44 if(mWordsList.size()==0){ 45 LrcHandle lrcHandler = new LrcHandle(); 46 lrcHandler.readLRC("/sdcard/"+name); 47 mWordsList = lrcHandler.getWords(); 48 } 49 super.onDraw(canvas); 50 canvas.drawColor(Color.BLACK); 51 Paint p = mLoseFocusPaint; 52 p.setTextAlign(Paint.Align.CENTER); 53 Paint p2 = mOnFocusePaint; 54 p2.setTextAlign(Paint.Align.CENTER); 55 canvas.drawText((String) mWordsList.get(mIndex), mX, mMiddleY, p2); 56 int alphaValue = 25; 57 float tempY = mMiddleY; 58 for (int i = mIndex - 1; i >= 0; i--) { 59 tempY -= DY; 60 if (tempY < 0) { 61 break; 62 } 63 p.setColor(Color.argb(255 - alphaValue, 245, 245, 245)); 64 canvas.drawText((String) mWordsList.get(i), mX, tempY, p); 65 alphaValue += 25; 66 } 67 alphaValue = 25; 68 tempY = mMiddleY; 69 for (int i = mIndex + 1, len = mWordsList.size(); i < len; i++) { 70 tempY += DY; 71 if (tempY > mY) { 72 break; 73 } 74 p.setColor(Color.argb(255 - alphaValue, 245, 245, 245)); 75 canvas.drawText((String) mWordsList.get(i), mX, tempY, p); 76 alphaValue += 25; 77 } 78 mIndex++; 79 } 80 81 @Override 82 protected void onSizeChanged(int w, int h, int ow, int oh) { 83 super.onSizeChanged(w, h, ow, oh); 84 mX = w * 0.5f; 85 mY = h; 86 mMiddleY = h * 0.3f; 87 } 88 89 // @SuppressLint("SdCardPath") 90 private void init() throws IOException { 91 setFocusable(true); 92 // LrcHandle lrcHandler = new LrcHandle(); 93 // lrcHandler.readLRC("/sdcard/wwyx.lrc"); 94 // mWordsList = lrcHandler.getWords(); 95 96 mLoseFocusPaint = new Paint(); 97 mLoseFocusPaint.setAntiAlias(true); 98 mLoseFocusPaint.setTextSize(22); 99 mLoseFocusPaint.setColor(Color.WHITE); 100 mLoseFocusPaint.setTypeface(Typeface.SERIF); 101 102 mOnFocusePaint = new Paint(); 103 mOnFocusePaint.setAntiAlias(true); 104 mOnFocusePaint.setColor(Color.YELLOW); 105 mOnFocusePaint.setTextSize(30); 106 mOnFocusePaint.setTypeface(Typeface.SANS_SERIF); 107 } 108 109 public String getName() { 110 return name; 111 } 112 113 public void setName(String name) { 114 this.name = name; 115 } 116 }
xml配置文件
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:orientation="vertical" 4 android:layout_width="fill_parent" 5 android:layout_height="fill_parent" 6 android:background="#FFFFFF" 7 > 8 <TableLayout 9 android:orientation="vertical" 10 android:layout_width="match_parent" 11 android:layout_height="wrap_content" 12 android:background="#FFFFFF" 13 > 14 <TableRow> 15 <ImageButton 16 android:id="@+id/ibgc1" 17 android:layout_width="wrap_content" 18 android:layout_height="wrap_content" 19 android:src="@drawable/hh" 20 android:background="#00000000" 21 android:layout_marginLeft="10px" 22 android:layout_marginRight="98px" 23 /> 24 </TableRow> 25 </TableLayout> 26 <TableLayout 27 android:orientation="vertical" 28 android:layout_width="fill_parent" 29 android:layout_height="wrap_content" 30 > 31 <TableRow> 32 <com.xm.WordView 33 android:id="@+id/text" 34 android:layout_width="330px" 35 android:layout_height="355px" 36 /> 37 </TableRow> 38 </TableLayout> 39 <TableLayout 40 android:orientation="horizontal" 41 android:layout_width="fill_parent" 42 android:layout_height="wrap_content" 43 android:background="#FFFFFF" 44 android:layout_alignParentBottom="true" 45 android:layout_marginTop="10px" 46 > 47 <TableRow> 48 <Button 49 android:id="@+id/bt10" 50 android:layout_width="wrap_content" 51 android:layout_height="wrap_content" 52 android:text="开始" 53 android:background="#FFFFFF" 54 android:layout_marginLeft="30px" 55 /> 56 <Button 57 android:id="@+id/bt11" 58 android:layout_width="wrap_content" 59 android:layout_height="wrap_content" 60 android:text="暂停" 61 android:background="#FFFFFF" 62 android:layout_marginLeft="180px" 63 /> 64 </TableRow> 65 </TableLayout> 66 </LinearLayout>
Activity类
1 private WordView mWordView; 2 private List mTimeList; 3 private MediaPlayer mPlayer; 4 private boolean isPause; 5 private boolean isStartTrackingTouch; 6 final Handler handler = new Handler(); 7 bt10 = (Button) findViewById(R.id.bt10); 8 bt10.setOnClickListener(new OnClickListener() { 9 @Override 10 public void onClick(View v) { 11 mPlayer.start(); 12 isPause = false; 13 new Thread(new Runnable() { 14 int i = 0; 15 @Override 16 public void run() { 17 while (mPlayer.isPlaying()) { 18 handler.post(new Runnable() { 19 @Override 20 public void run() { 21 mWordView.invalidate(); 22 } 23 }); 24 try { 25 int a = Integer.parseInt(String.valueOf(mTimeList 26 .get(i + 1))); 27 int b = Integer.parseInt(String.valueOf(mTimeList 28 .get(i))); 29 Thread.sleep(a - b); 30 } catch (Exception e) { 31 } 32 i++; 33 if (i == mTimeList.size() - 1) { 34 mPlayer.stop(); 35 break; 36 } 37 } 38 } 39 }).start(); 40 } 41 }); 42 bt11 = (Button) findViewById(R.id.bt11); 43 bt11.setOnClickListener(new OnClickListener() { 44 @Override 45 public void onClick(View v) { 46 mPlayer.pause(); 47 isPause = true; 48 } 49 }); 50 LrcHandle lrcHandler = new LrcHandle(); 51 String name1 = getIntent().getStringExtra("name"); 52 String str=name1.substring(0,name1.indexOf('.')); 53 String str1=str+".lrc"; 54 String name2 = getIntent().getStringExtra("name"); 55 mWordView = (WordView) findViewById(R.id.text); 56 mWordView.setName(str1); 57 mPlayer = new MediaPlayer(); 58 mPlayer.reset(); 59 try { 60 lrcHandler.readLRC("/sdcard/"+str1); 61 mTimeList = lrcHandler.getTime(); 62 mPlayer.setDataSource("/sdcard/"+name2); 63 mPlayer.prepare(); 64 } catch (IOException e) { 65 e.printStackTrace(); 66 } catch (IllegalArgumentException e) { 67 e.printStackTrace(); 68 } catch (SecurityException e) { 69 e.printStackTrace(); 70 } catch (IllegalStateException e) { 71 e.printStackTrace(); 72 }