Android - 自定义View 实现 文本吉他谱的 显示 实现

来源:互联网 发布:冒险岛766新版数据库 编辑:程序博客网 时间:2024/04/27 08:12

1.背景

    难点1 :显示:文本吉他谱是txt ,需要 和弦键与对应的文字对应显示出来;

    难点2: 控制:需要通过音量键进行动态的控制,+ ,向下控制当前的和弦键,-,向上控制当前的和弦键;(完成)

    难点3: 显示:当前控制的和弦键需要放大和变颜色,和当前行歌词颜色,正常行歌词颜色,均不一样;(完成)

    难点4: 控制:通过和弦键来控制整体歌词的滚动;(完成)

    难点5: 回调:需要回调 当前正在使用的和弦键,和下一个和弦键;(完成)

     效果:

                                

  

2.难点1 实现失败过程

     在这里我没有实现对应和弦键与歌词的对应关系的实现;我认为太多的因素,比如人为因素,以至于无法确定显示的效果;如果哪位前辈,解决了这个问题,还请赐教,谢谢。在此期间我想过几种方式;

     (1)不转换任何格式,直接进行显示

                   通过肉眼的计算,发现两个空格对应1个汉字,就将其中的空格数除以2,进行输出;具体算法实现:

private synchronized String parseLrcKeyString(String lrcKey){StringBuffer buffer=new StringBuffer();//字符串方式分割String[] split = lrcKey.split(" ");int space=1;for(int i=0;i<split.length;i++){//不为""的两个字符之间添加 长度/2个全角空格//1.计数空格if(split[i].equals("")){//是空格space++;}else{//不是空格space=(int) Math.ceil(space/2);for(int j=0;j<space;j++){buffer.append(" ");}//mNormalPaint.mebuffer.append(split[i]);space=1;}}return buffer.toString();}

           结果:失败,从显示的角度上,有的是可以显示成功的,有的是显示不成功的;

  (2)第二种方式:经过计算的方式,通过查询资料和测试,发现全角下的空格和汉字的长度一致,于是,就将歌词中的空格进行了替换,将多个空格替换为一个全角空格,代表一个汉字的存在;

             这是找到切入点,就是空格的个数是固定的,和弦之间,和弦之前,空格的个数均是固定不变的,根据长度四个半角空格的显示宽度等于1个全角空格的宽度,也就是一个汉字的宽度,这样来计算的话,应该是可以实现的;

           具体算法实现:

/** * 操作单个字符 * @param canvas * @param currX * @param centerY * @param lrcKey * @param paint * @param currentLine */private synchronized void parseLrcKeyStr1(Canvas canvas,float currX,float centerY,String lrcKey,Paint paint,int currentLine){//字符串方式分割String[] split = lrcKey.split(" ");int space=1;    float spaceLength=24.0f;float length=0;float sl=0;for(int i=0;i<split.length;i++){//不为""的两个字符之间添加 长度/2个全角空格//1.计数空格String str = split[i];str = halfToFull(str);if(str.equals("")||str==""){//是空格space++;}else{space=space/2;for(int j=0;j<space;j++){canvas.drawText(" ",currX+length, centerY, paint);length+=spaceLength/2;}float f = paint.measureText(str);if(mCurrentLine==0){   System.out.println("----------------"+f);}if(f>40.0f&&f<50.0f){sl=f-60.0f;}else if(f>50.0f){sl=f-98.0f;}else{sl=f-36.0f;}length+=sl;//确定当前的和弦,1,和弦值一样,2,当前值一样 ,3,str=fullToHalf(str);if(nowChord.equals(str)){canvas.drawText(str,currX+length, centerY, nowChordPaint);}else{    canvas.drawText(str,currX+length, centerY, paint);}length=length-sl+f;space=1;}}}

        这里开始进行了,绘制是之间进行绘制的,不在返回,便于操作;

        结果:失败,通过计算出来的,也不行,通过测试字符串的宽度,并没有问题,显示有问题,很纠结,找不到原因,未解决;


3.难点3实现

    难点3 是 当为那个和弦键的时候,需要切换到该和弦键,且该和弦键放大,和变颜色,(问题 A:在这里又要引出一个问题,当放大的时候,字符宽度就要改变,上面通过计算的方式,是不是又要麻烦了)!!!

   效果 :

                                                              

    就好比图中的Am一样,变色且放大,这里的实现思路,在上面的方法中一样有所体现:

    (1)在计算方法中绘制 ,边计算边绘制;

    (2)切入点有三:当前绘制的和弦键Am, 当前行(当前操作的和弦行mCurrentLine),当前列(和弦键所在数组的index);

       (3) 问题来了,如果和弦键一样,那么将全部绘制,所以我们将其标示为唯一的;

            实现算法:

/** * 得到字符串数组 * @param lrcKey * @return */private String[] getSplitStringArray(String lrcKey) {String[] split = lrcKey.split(" ");    int splitIndex=0;    for(int i=0;i<split.length;i++){    if(!split[i].equals("")){    split[i]=split[i]+splitIndex;    splitIndex++;    }    }return split;}
 
      哈哈,问题B : 这里将每个和弦键后面加了单个数字,计算的时候,长度又变了,计算的方式还可以使用吗?!

    当然绘制的时候,肯定要将数字消掉;

  (4)绘制算法实现

/** * 绘制 * @param canvas * @param currX * @param centerY * @param lrcKey * @param paint * @param currentLine */int nowLineChords=0;private String needChords=null;private synchronized void parseLrcKeyStr(Canvas canvas,float currX,float centerY,String lrcKey,Paint paint,int currentLine){//字符串方式分割String[] split = getSplitStringArray(lrcKey);        float spaceLength=mCurrentPaint.measureText(" ");    if(currentLine==mCurrentLine){    System.out.println("nowLineChords : "+nowLineChords+" chordsIndex:"+chordsIndex);    Log.d("Lrc", "needChords: "+needChords + " ");    }    float length=0;float sl=0;for(int i=0;i<split.length;i++){//不为""的两个字符之间添加 长度/2个全角空格//1.计数空格String str = split[i];if(str.equals("")||str==""){//是空格canvas.drawText(" ",currX+length, centerY, paint);length+=spaceLength*2;}else{float f = paint.measureText(str);//半角的if(f>30.0f&&f<40.0f){sl=f/5*2;}else if(f>=40.0f){sl=f/4;}else{sl=f/2;}length+=sl;//确定当前的和弦,1,和弦值一样,2,当前值一样 ,3,if(needChords.equals(str) && mCurrentLine==currentLine && nowLineChords==chordsIndex){  str=str.substring(0,str.length()-1);  canvas.drawText(str,currX+length, centerY, nowChordPaint);}else{str=str.substring(0,str.length()-1);    canvas.drawText(str,currX+length, centerY, paint);}length=length-sl+f;}}}

4.整个LrcView实现

package cn.labelnet.weiget;import java.io.BufferedReader;import java.io.File;import java.io.FileReader;import java.io.InputStreamReader;import java.lang.ref.WeakReference;import java.text.ChoiceFormat;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.regex.Matcher;import java.util.regex.Pattern;import android.animation.ValueAnimator;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Typeface;import android.os.Environment;import android.os.Handler;import android.os.Message;import android.util.AttributeSet;import android.util.Log;import android.util.SparseArray;import android.view.View;/** * LrcView 基本思路 : 1.加载txt 2.解析 ,给 和弦的最后加上 # 以标记 3.解析分别进行存储,当前行没有 # 号,存储 为 no ,为 * 当前行歌词 4.解析有# 则进行 存储,切读取下一行进行存储 5.传入参数进行播放 6.切换 7. *  */public class LrcView extends View {private static final String TAG = LrcView.class.getSimpleName();private static final int MSG_NEW_LINE = 0;private static final String MSG_KEY_NO = "no";// 数据private List<String> mLrcKeys;private List<String> mLrcTexts;private LrcHandler mHandler;// 绘制private Paint mNormalPaint;private Paint mCurrentPaint;// 初始化参数private float mTextSize;private float mDividerHeight;private long mAnimationDuration;private int mCurrentLine = 0;private float mAnimOffset;// 计数器private int mNext = -1;// 总行数private int rowNums = 0;// 和弦private String[] chords = null;//和弦集合,反向存储 和弦键及其位置private Map<String,Integer> chordsList=new HashMap<String, Integer>();// 和弦计数器private int chordsIndex = -1;// 当前的和弦键private String nowChord = MSG_KEY_NO;// 记录上一次执行的操作private int preX = 0;// 下一个和弦键的下标private int nextChordsIndex = chordsIndex;// 当前行private int nextCurrentRow = mCurrentLine;// 下一个和弦值private String nextChord = MSG_KEY_NO;// 回调接口private LrcViewInterface lrcViewInterface;//显示处理private Pattern p = Pattern.compile("\\s+");//绘制和弦的画笔private Paint chordPaint;private Paint nomalChordPaint;private Paint nowChordPaint;public void setLrcViewInterface(LrcViewInterface lrcViewInterface) {this.lrcViewInterface = lrcViewInterface;}public LrcView(Context context) {this(context, null);}public LrcView(Context context, AttributeSet attrs) {super(context, attrs);init(attrs);}/** * @param attrs */private void init(AttributeSet attrs) {// 初始化mTextSize = 24.0f;mDividerHeight = 72.0f;mAnimationDuration = 1000;mAnimationDuration = mAnimationDuration < 0 ? 1000 : mAnimationDuration;mLrcKeys = new ArrayList<String>();mLrcTexts = new ArrayList<String>();WeakReference<LrcView> lrcViewRef = new WeakReference<LrcView>(this);mHandler = new LrcHandler(lrcViewRef);mNormalPaint = new Paint();mCurrentPaint = new Paint();mNormalPaint.setColor(Color.BLACK);mNormalPaint.setTextSize(mTextSize);mCurrentPaint.setColor(Color.RED);mCurrentPaint.setTextSize(mTextSize);mCurrentPaint.setAntiAlias(true);mNormalPaint.setAntiAlias(true);chordPaint=new Paint();chordPaint.setTextSize(mTextSize);chordPaint.setColor(Color.RED);chordPaint.setAntiAlias(true);nomalChordPaint=new Paint();nomalChordPaint.setTextSize(mTextSize);nomalChordPaint.setColor(Color.BLACK);nomalChordPaint.setAntiAlias(true);nowChordPaint=new Paint();nowChordPaint.setTextSize(30.0f);nowChordPaint.setColor(Color.GREEN);nowChordPaint.setAntiAlias(true);//设置字体mCurrentPaint.setTypeface(Typeface.SANS_SERIF);mNormalPaint.setTypeface(Typeface.SANS_SERIF);chordPaint.setTypeface(Typeface.SANS_SERIF);nowChordPaint.setTypeface(Typeface.SANS_SERIF);nomalChordPaint.setTypeface(Typeface.SANS_SERIF);}@Overrideprotected synchronized void onDraw(Canvas canvas) {super.onDraw(canvas);if (mLrcKeys.isEmpty() || mLrcTexts.isEmpty()) {return;}// 中心Y坐标float centerY = getHeight() / 2 + mTextSize / 2 + mAnimOffset;// 画当前行String currStr = mLrcTexts.get(mCurrentLine);String currKey = mLrcKeys.get(mCurrentLine);float currX = (getWidth() - mCurrentPaint.measureText(currStr)) / 2;if (!MSG_KEY_NO.equals(currKey)) {parseLrcKeyStr(canvas,currX,centerY-30,currKey,chordPaint,mCurrentLine);}canvas.drawText(currStr, currX, centerY, mCurrentPaint);// 画当前行上面的for (int i = mCurrentLine - 1; i >= 0; i--) {String upStr = mLrcTexts.get(i);String upKey = mLrcKeys.get(i);float upX = (getWidth() - mNormalPaint.measureText(upStr)) / 2;float upY = centerY - (mTextSize + mDividerHeight)* (mCurrentLine - i);if (!MSG_KEY_NO.equals(upKey)) {parseLrcKeyStr(canvas,upX,upY-30,upKey,nomalChordPaint,i);}canvas.drawText(upStr, upX, upY, mNormalPaint);}// 画当前行下面的for (int i = mCurrentLine + 1; i < mLrcKeys.size(); i++) {String downStr = mLrcTexts.get(i);String downKey = mLrcKeys.get(i);float downX = (getWidth() - mNormalPaint.measureText(downStr)) / 2;float downY = centerY + (mTextSize + mDividerHeight)* (i - mCurrentLine);if (!MSG_KEY_NO.equals(downKey)) {parseLrcKeyStr(canvas,downX,downY-30,downKey,nomalChordPaint,i);}canvas.drawText(downStr, downX, downY, mNormalPaint);}}/** * 绘制 * @param canvas * @param currX * @param centerY * @param lrcKey * @param paint * @param currentLine */int nowLineChords=0;private String needChords=null;private synchronized void parseLrcKeyStr(Canvas canvas,float currX,float centerY,String lrcKey,Paint paint,int currentLine){//字符串方式分割String[] split = getSplitStringArray(lrcKey);        float spaceLength=mCurrentPaint.measureText(" ");    if(currentLine==mCurrentLine){    System.out.println("nowLineChords : "+nowLineChords+" chordsIndex:"+chordsIndex);    Log.d("Lrc", "needChords: "+needChords + " ");    }    float length=0;float sl=0;for(int i=0;i<split.length;i++){//不为""的两个字符之间添加 长度/2个全角空格//1.计数空格String str = split[i];if(str.equals("")||str==""){//是空格canvas.drawText(" ",currX+length, centerY, paint);length+=spaceLength*2;}else{float f = paint.measureText(str);//半角的if(f>30.0f&&f<40.0f){sl=f/5*2;}else if(f>=40.0f){sl=f/4;}else{sl=f/2;}length+=sl;//确定当前的和弦,1,和弦值一样,2,当前值一样 ,3,if(needChords.equals(str) && mCurrentLine==currentLine && nowLineChords==chordsIndex){  str=str.substring(0,str.length()-1);  canvas.drawText(str,currX+length, centerY, nowChordPaint);}else{str=str.substring(0,str.length()-1);    canvas.drawText(str,currX+length, centerY, paint);}length=length-sl+f;}}}/** * 得到字符串数组 * @param lrcKey * @return */private String[] getSplitStringArray(String lrcKey) {String[] split = lrcKey.split(" ");    int splitIndex=0;    for(int i=0;i<split.length;i++){    if(!split[i].equals("")){    split[i]=split[i]+splitIndex;    splitIndex++;    }    }return split;}// 功能:字符串全角转换为半角// 说明:全角空格为12288,半角空格为32//  其他字符全角(65281-65374)与半角(33-126)的对应关系是:均相差65248 // 输入参数:input -- 需要转换的字符串// 输出参数:无:// 返回值: 转换后的字符串public static String fullToHalf(String input) {  char[] c = input.toCharArray();  for (int i = 0; i< c.length; i++) {         if (c[i] == 12288) //全角空格       {         c[i] = (char) 32;           continue;         }        if (c[i]> 65280&& c[i]< 65375)            c[i] = (char) (c[i] - 65248);  }  return new String(c);  }// 功能:字符串半角转换为全角// 说明:半角空格为32,全角空格为12288.// 其他字符半角(33-126)与全角(65281-65374)的对应关系是:均相差65248// 输入参数:input -- 需要转换的字符串// 输出参数:无:// 返回值: 转换后的字符串public static String halfToFull(String input) {char[] c = input.toCharArray();for (int i = 0; i < c.length; i++) {if (c[i] == 32) // 半角空格{c[i] = (char) 12288;continue;}// 根据实际情况,过滤不需要转换的符号// if (c[i] == 46) //半角点号,不转换// continue;if (c[i] > 32 && c[i] < 127) // 其他符号都转换为全角c[i] = (char) (c[i] + 65248);    }return new String(c);}public void loadSDLrc(String lrcName) throws Exception {mLrcTexts.clear();mLrcKeys.clear();File file = new File(Environment.getExternalStorageDirectory(), lrcName);BufferedReader br = new BufferedReader(new FileReader(file));String line;int index = 0;while ((line = br.readLine()) != null) {// 单行加载解析// line = halfToFull(line);// 1.判断最后是否有 $ 符号index = line.lastIndexOf("$");if (index > 0) {// 则此行为 和弦行,进行解析,存储下一行数据// 存储和弦值line = line.substring(0, index);mLrcKeys.add(line);// 存储对应的歌词line = br.readLine();if (line != null) {mLrcTexts.add(line);} else {break;}} else {// 没有$符号,存储歌词,存储和弦为nomLrcKeys.add(MSG_KEY_NO);mLrcTexts.add(line);}}br.close();// 记录总行数rowNums = mLrcTexts.size();for (int i = 0; i < mLrcKeys.size() - 1; i++) {Log.d("Lrc", mLrcKeys.get(i));}Log.d("Lrc", " mLrcKeys : " + mLrcKeys.size());Log.d("Lrc", " mLrcTexts : " + mLrcTexts.size());}/** * * @param lrcName *            assets下的歌词文件名 * @throws Exception */public void loadLrc(String lrcName) throws Exception {mLrcTexts.clear();mLrcKeys.clear();BufferedReader br = new BufferedReader(new InputStreamReader(getResources().getAssets().open(lrcName)));String line;int index = 0;while ((line = br.readLine()) != null) {// 单行加载解析// // 1.判断最后是否有 $ 符号index = line.lastIndexOf("$");if (index > 0) {// 则此行为 和弦行,进行解析,存储下一行数据// 存储和弦值line = line.substring(0, index);mLrcKeys.add(line);// 存储对应的歌词line = br.readLine();if (line != null) {mLrcTexts.add(line);} else {break;}} else {// 没有$符号,存储歌词,存储和弦为nomLrcKeys.add(MSG_KEY_NO);Matcher m = p.matcher(line);line= m.replaceAll(" ");mLrcTexts.add(line);}}br.close();// 记录总行数rowNums = mLrcTexts.size();for (int i = 0; i < mLrcKeys.size() - 1; i++) {Log.d("Lrc", mLrcKeys.get(i));}Log.d("Lrc", " mLrcKeys : " + mLrcKeys.size());Log.d("Lrc", " mLrcTexts : " + mLrcTexts.size());}/** * 当一行的和弦执行全部切换完毕的时候,进行下一行切换 基本思路: 内部计数器,总行数; 1. x=1 ,进行下一个和弦的更新 *  * 2.x=-1,进行上一个和旋的更新 3. 先得到 当前行的所有和弦, 如果有和弦 * :将和弦进行解析,后有一个计数器,进行计数;当计数器没有等于和弦总个数的时候,进行下一行显示 如果没有和弦,直接进行下一行显示 * 下一行显示之前,先进行和弦判断 *  * @param x *            , -1 , 1 */public synchronized void updateLrc(int x) {Log.d("Lrc","-----------------------2---------------------------");Log.d("Lrc", "chordsIndex 1: " + chordsIndex);//临界值1,第一行if(x<0){if(mNext==0){//判定有和弦没有if(chordsIndex==-1){//没有和弦lrcViewInterface.isPlayToTop(true);return;}else{//有和弦if(preX<0){if(chordsIndex==0){//第一个Log.d("Lrc", "临界值1 : ");chordsIndex=1;lrcViewInterface.isPlayToTop(true);return;}}if(preX>0){if((chordsIndex-1)==0){//判定是不是第一个元素Log.d("Lrc", "临界值2: ");lrcViewInterface.isPlayToTop(true);return;}}}}}//临界值2: 最后一行了,不在进行更新操作if (x > 0) {if (mNext >= rowNums - 1) {//判定是否有和弦if(chordsIndex==-1){//没有和弦lrcViewInterface.isPlayToEnd(true);return;}else{//有和弦,判定是否等于数组长度if(chordsIndex==chords.length){//最后一个和弦了lrcViewInterface.isPlayToEnd(true);return;}}}}if (chordsIndex == -1) {// 如果chordsIndex等于-1 ,代表着 这一行没有 和弦,则进行滚动到下一行// x是1还是-1,如果是1,则代表向下一行,是-1则代表向上一行;parseLine(x);}Log.d("Lrc", "chordsIndex 2: " + chordsIndex);if (chords != null) {// 判断当前执行的动作和上一次执行的动作是否一样,// 如果一样,不进行chordsIndex操作,如果不一样,分别对其进行不同的操作if (preX == -1 && x == 1)  {if(chordsIndex != 0){    chordsIndex += 1;}} else if (preX == 1 && x == -1) {chordsIndex -= 1;}// 不等于空,开始控制switch (x) {case 1:// 下一个和弦的切换,更新界面,不更新行// 最后一个和弦if (chords.length == chordsIndex) {// 临界值为最大的时候,切换下一行parseLine(1);if (chordsIndex > -1) {nowChord = chords[chordsIndex];Log.d("Lrc", "和弦 +1 if: " + nowChord);chordsIndex++;}} else {nowChord = chords[chordsIndex];Log.d("Lrc", "和弦 +1 else : " + nowChord);chordsIndex++;} Log.d("Lrc", "chordsIndex 3 : " + chordsIndex); needChords=nowChord+(chordsIndex-1);break;case -1:chordsIndex--;chordsIndex = chordsIndex < -1 ? -1 : chordsIndex;// 上一个和弦的切换,更新界面,不更新行// Log.d("Lrc", "和弦 -1 执行了");Log.d("Lrc", "chordsIndex -3: " + chordsIndex);if (chordsIndex == -1) {// 临界值为最小的时候,切换上一行parseLine(-1);if (chordsIndex > -1) {chordsIndex--;nowChord = chords[chordsIndex];Log.d("Lrc", "和弦 if -1 : " + nowChord);}} else {nowChord = chords[chordsIndex];Log.d("Lrc", "和弦 else -1 : " + nowChord);}Log.d("Lrc", "chordsIndex -4: " + chordsIndex); needChords=nowChord+chordsIndex;break;}// 这里是上面绘制,将单个和弦绘制的控制条件nowLineChords=chordsIndex;//if(x>0){//  needChords=nowChord+(chordsIndex-1);//}////if(x<0){////}} else {Log.d("Lrc", "和弦数组chords 为空了: ");}preX = x;// 获得下一个和弦键nextChordsIndex = x > 0 ? chordsIndex : chordsIndex + 1;getNextChord();// 和弦回调lrcViewInterface.getNowChordAndNextChord(nowChord, nextChord);Log.d("Lrc", "needChords: "+needChords);invalidate();}/** * 1. 解析当前行的和弦 */private void parseLine(int isNext) {if (isNext > 0) {mNext++;} else {mNext--;}mCurrentLine = mNext == rowNums ? 0 : mNext;mCurrentLine = mNext < 1 ? 0 : mNext;mNext = mCurrentLine;chords = null;chordsList.clear();// 获得当前的和弦String key = mLrcKeys.get(mCurrentLine);// 解析if (MSG_KEY_NO.equals(key)) {chordsIndex = -1;// 没有和弦,更新下一行mHandler.sendEmptyMessage(MSG_NEW_LINE);} else {// 有和弦chords = key.trim().split("\\s+");// 测试String t = " ";for (int i = 0; i < chords.length; i++) {t += chords[i] + " ";chordsList.put(chords[i]+i,i);}Log.d("Lrc", "和弦 :" + t);Log.d("Lrc", "歌词 :" + mLrcTexts.get(mCurrentLine));// 如果进行下一行,则if (isNext < 0) {chordsIndex = chords.length;} else {chordsIndex = 0;}mHandler.sendEmptyMessage(MSG_NEW_LINE);}}// 3. 获得下一个和弦值/* * 基本思路: *  * 根据当前和弦键的下标+1=下一个和弦下标, 如果下标==数组长度, 则向下循环遍历 下面的和弦,取得最近的和弦返回即可 *  * !=数组长度,返回即可 */public void getNextChord() {if (nextChordsIndex == -1) {return;}if (chords != null) {if (nextChordsIndex >= chords.length) {// 当前行+1nextCurrentRow = mCurrentLine + 1;for (int i = nextCurrentRow; i < rowNums; i++) {String lrcKey = mLrcKeys.get(i);if (lrcKey.equals(MSG_KEY_NO)) {continue;} else {// 有和弦的行,取得第一个返回nextChord = lrcKey.trim().split("\\s+")[0];break;}}} else {if (nextChordsIndex > 0) {nextChord = chords[nextChordsIndex];}}}}/** * 换行动画 Note:属性动画只能在主线程使用 */private void newLineAnim() {ValueAnimator animator = ValueAnimator.ofFloat(mTextSize+ mDividerHeight, 0.0f);animator.setDuration(mAnimationDuration);animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {mAnimOffset = (Float) animation.getAnimatedValue();invalidate();}});animator.start();}private static class LrcHandler extends Handler {private WeakReference<LrcView> mLrcViewRef;public LrcHandler(WeakReference<LrcView> lrcViewRef) {mLrcViewRef = lrcViewRef;}@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case MSG_NEW_LINE:LrcView lrcView = mLrcViewRef.get();if (lrcView != null) {lrcView.newLineAnim();}break;}super.handleMessage(msg);}}// 回调接口public interface LrcViewInterface {// 回调出来 当前的和弦,和下一个和弦void getNowChordAndNextChord(String nowChord, String nextChord);void isPlayToEnd(boolean isToEnd);void isPlayToTop(boolean isToTop);}}

5.调用实现

   实现LrcView中的接口进行回调实现;

package cn.labelnet.lrcview;import android.app.Activity;import android.os.Bundle;import android.view.KeyEvent;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.TextView;import android.widget.Toast;import cn.labelnet.weiget.LrcView;import cn.labelnet.weiget.LrcView.LrcViewInterface;public class MainActivity extends Activity implements OnClickListener,LrcViewInterface {private LrcView view_lrc;private Button btn_add, btn_remove;private TextView tv_nowChord, tv_nextChord;/** * 控制已实现 还需要做的 : 1. 对应关系及其显示 2. 歌词过长处理 */@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);tv_nowChord = (TextView) findViewById(R.id.tv_nowChord);tv_nextChord = (TextView) findViewById(R.id.tv_nextChord);btn_add = (Button) findViewById(R.id.btn_add);btn_add.setOnClickListener(this);btn_remove = (Button) findViewById(R.id.btn_remove);btn_remove.setOnClickListener(this);view_lrc = (LrcView) findViewById(R.id.view_lrc);view_lrc.setLrcViewInterface(this);try {// view_lrc.loadSDLrc("dang.txt");view_lrc.loadLrc("lrc.txt");view_lrc.updateLrc(1);} catch (Exception e) {e.printStackTrace();}}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.btn_add:// 点击增加模拟view_lrc.updateLrc(1);break;case R.id.btn_remove:// 点击减少模拟view_lrc.updateLrc(-1);break;}}@Overridepublic void getNowChordAndNextChord(String nowChord, String nextChord) {tv_nowChord.setText(nowChord);tv_nextChord.setText(nextChord);}@Overridepublic void isPlayToEnd(boolean isToEnd) {if (isToEnd) {showToast("播放完毕了");}}public void showToast(String msg) {Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();}@Overridepublic void isPlayToTop(boolean isToTop) {showToast("准备开始");}//音量键监听@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {switch (keyCode) {case KeyEvent.KEYCODE_VOLUME_UP:// 音量键+view_lrc.updateLrc(1);break;case KeyEvent.KEYCODE_VOLUME_DOWN:// 音量键-view_lrc.updateLrc(-1);break;}return super.onKeyDown(keyCode, event);}}

6.Demo下载

  http://download.csdn.net/detail/lablenet/9407043

  GitHub 交流: https://github.com/LABELNET/LrcView


0 0
原创粉丝点击