歌词滚动

1.以前的滚动只是安行来刷新,现在不是按行来滚动了,其实就是在一定时间内整体往上移动,比如说在1S内刷新10次,由于认得肉眼看起来像是滚动。

关键代码如下:

view plaincopy to clipboardprint?
float plus = currentDunringTime == 0 ? 30  
        : 30  
                + (((float) currentTime - (float) sentenctTime) / (float) currentDunringTime)  
                * (float) 30;  
// 向上滚动 这个是根据歌词的时间长短来滚动,整体上移  
canvas.translate(0, -plus);  


plus就是每次移动的大小,它就是根据歌词所持续的时间来计算的,时间越长,plus的值就越小。具体的看代码了。



下面就是获取歌词的信息:



view plaincopy to clipboardprint?
public void updateIndex(long time) {  
    this.currentTime = time;  
    // 歌词序号  
    index = mLyric.getNowSentenceIndex(time);  
    if (index != -1) {  
        Sentence sen = Sentencelist.get(index);  
        sentenctTime = sen.getFromTime();  

        currentDunringTime = sen.getDuring(); 





    }  
}  




以下就是跟新线程:

view plaincopy to clipboardprint?
class UIUpdateThread implements Runnable {  
    long time = 100; // 滚动速度  
    public void run() {  
        while (mp.isPlaying()) {  
            lyricView.updateIndex(mp.getCurrentPosition());  
            mHandler.post(mUpdateResults);  
            try {  
                Thread.sleep(time);  
            } catch (InterruptedException e) {  
                // TODO Auto-generated catch block  
                e.printStackTrace();  
            }  
        }  
    }  

}






  网上androi播放器虽然挺多,感觉提供的歌词显示功能比较死板,要么搜索给的条件死死的,要么放置sdcard内部的歌词格式需要统一,应该提供类似文件夹浏览的功能。^_^,不过在这之前先搞定歌词的现实界面:

      转载请注明http://ishelf.iteye.com/admin/blogs/740402

      播放器的歌词界面实现以下几个功能

  1. 根据歌曲的播放进度自下而上滚动;
  2. 提供上下拖动调整歌曲进度的功能;
  3. 突出显示当前进度的歌词段,并保证该歌词段处于布局中心

     不多说了直接贴代码,首先开启一个线程每隔一段时间往view中送入一串字符

Java代码   收藏代码
  1. import android.os.Bundle;  
  2. import android.os.Handler;  
  3. import android.view.View;  
  4. import android.view.View.OnClickListener;  
  5. import android.widget.Button;  
  6.   
  7. public class TextAlign extends GraphicsActivity implements OnClickListener {  
  8.   
  9.     private SampleView mView;  
  10.   
  11.     @Override  
  12.     protected void onCreate(Bundle savedInstanceState) {  
  13.         super.onCreate(savedInstanceState);  
  14.         // Animation in = AnimationUtils.loadAnimation(this, R.anim.push_up_in);  
  15.   
  16.         // mView.setAnimation(in);  
  17.         setContentView(R.layout.main);  
  18.         mView =(SampleView) findViewById(R.id.text01);  
  19.   
  20.         Button bt = (Button) findViewById(R.id.Button01);  
  21.         bt.setOnClickListener(this);  
  22.           
  23.         new Thread(new UIUpdateThread()).start();  
  24.   
  25.     }  
  26.   
  27.     class UIUpdateThread implements Runnable {  
  28.         long time = 40000;  
  29.   
  30.         long sleeptime = 100;  
  31.         public void run() {  
  32.             try {  
  33.                 while (time < 200000) {  
  34.                     Thread.sleep(sleeptime);  
  35.                     mView.updateIndex(time);//.index = mLyric.getNowSentenceIndex(time);  
  36. //                  Log.v("UIThread", mView.index + ":" + time);  
  37.                     time += sleeptime;  
  38.                     mHandler.post(mUpdateResults);  
  39.                 }  
  40.             } catch (InterruptedException e) {  
  41.                 e.printStackTrace();  
  42.             }  
  43.         }  
  44.     }  
  45.     Handler mHandler = new Handler();  
  46.     Runnable mUpdateResults = new Runnable() {  
  47.         public void run() {  
  48.             mView.invalidate(); // 更新视图  
  49.         }  
  50.     };  
  51.   
  52.     @Override  
  53.     public void onClick(View v) {  
  54.         mView.mTouchHistoryY -=30;  
  55.         mHandler.post(mUpdateResults);  
  56.     }  
  57. }  

     这里将时间送到SampleView中,该类对此时间进行加工得到一系列list(该list是动态生成的),从而根据时间的推移递增的得到一系列的字串。这个过程模拟了歌词的显示过程

      接下来的SampleView继承了TextView并重载了onDraw方法.注意,这里只给了个sample,里面歌词怎么生成的见YOYOPlayer。这里就不给代码了

Java代码   收藏代码
  1. import java.io.File;  
  2. import java.util.List;  
  3.   
  4. import android.content.Context;  
  5. import android.graphics.Canvas;  
  6. import android.graphics.Color;  
  7. import android.graphics.Paint;  
  8. import android.graphics.Path;  
  9. import android.graphics.Typeface;  
  10. import android.util.AttributeSet;  
  11. import android.util.Log;  
  12. import android.view.MotionEvent;  
  13. import android.widget.TextView;  
  14. import android.widget.Toast;  
  15.   
  16. import com.android.lyric.Lyric;  
  17. import com.android.lyric.PlayListItem;  
  18. import com.android.lyric.Sentence;  
  19.   
  20. public class SampleView extends TextView {  
  21.         private Paint mPaint;  
  22.         private float mX;  
  23.         private static Lyric mLyric;  
  24.   
  25.         private Path mPath;  
  26.         private Paint mPathPaint;  
  27.         public String test = "test";  
  28.         public int index = 0;  
  29.         private List<Sentence> list;  
  30.   
  31.         private float mTouchStartY;  
  32.         private float mTouchCurrY;  
  33.         public float mTouchHistoryY;  
  34.   
  35.         private int mY;  
  36.         private long currentTime;  
  37.         private long currentDunringTime;  
  38.         private long sentenctTime;  
  39.         private float middleY;  
  40.         private String middleContent="Empty";  
  41.         private static final int DY = 30;  
  42.   
  43.         private static void makePath(Path p) {  
  44.             p.moveTo(100);  
  45.             p.cubicTo(100, -50200503000);  
  46.         }  
  47.   
  48.   
  49.         public SampleView(Context context) {  
  50.             super(context);  
  51.             init();  
  52.         }  
  53.         public SampleView(Context context,AttributeSet attr) {  
  54.             super(context,attr);  
  55.             init();  
  56.         }  
  57.         public SampleView(Context context,AttributeSet attr,int i) {  
  58.             super(context,attr,i);  
  59.             init();  
  60.         }  
  61.   
  62.         private void init() {  
  63.             setFocusable(true);  
  64.             PlayListItem pli = new PlayListItem("""", 1000L, true);  
  65.             mLyric = new Lyric(new File("/sdcard/M0005044007.lrc"), pli);  
  66.   
  67.             list = mLyric.list;  
  68.             mPaint = new Paint();  
  69.             mPaint.setAntiAlias(true);  
  70.             mPaint.setTextSize(20);  
  71.             mPaint.setTypeface(Typeface.SERIF);  
  72.   
  73.   
  74.             mPath = new Path();  
  75.             makePath(mPath);  
  76.   
  77.             mPathPaint = new Paint();  
  78.             mPathPaint.setAntiAlias(true);  
  79.             mPathPaint.setColor(0x800000FF);  
  80.             mPathPaint.setStyle(Paint.Style.STROKE);  
  81.         }  
  82.   
  83.           
  84.         @Override  
  85.         protected void onDraw(Canvas canvas) {  
  86.             super.onDraw(canvas);  
  87.   
  88.             canvas.drawColor(Color.WHITE);  
  89.   
  90.             Paint p = mPaint;  
  91.             float x = mX;  
  92.             float plus =currentDunringTime==0?index*30: index*30 +(((float)currentTime - (float)sentenctTime)/(float)currentDunringTime)*(float)30;  
  93.             float y =  mY- plus+mTouchCurrY - mTouchStartY+mTouchHistoryY;  
  94.                   
  95.             canvas.translate(0,y);  
  96.   
  97.             for (int i = 0; i < index; i++) {  
  98.                 String text = list.get(i).getContent();  
  99.                 if((y+i*30)<=middleY&&(y+i*30+30)>=middleY)  
  100.                     middleContent = text;  
  101.                 p.setTextAlign(Paint.Align.CENTER);  
  102.                 canvas.drawText(text, x, 0, p);  
  103.                 // mY- mY/lines*(index - i)  
  104.                 canvas.translate(0, DY);  
  105.             }  
  106.         }  
  107.   
  108.   
  109.         @Override  
  110.         protected void onSizeChanged(int w, int h, int ow, int oh) {  
  111.             super.onSizeChanged(w, h, ow, oh);  
  112.             mX = w * 0.5f; // remember the center of the screen  
  113.             mY = h;  
  114.             middleY = h*0.5f;  
  115.         }  
  116.   
  117.         @Override  
  118.         public boolean onTouchEvent(MotionEvent event) {  
  119.             float y = event.getY();  
  120.   
  121.             switch (event.getAction()) {  
  122.             case MotionEvent.ACTION_DOWN:  
  123.                 mTouchHistoryY += mTouchCurrY - mTouchStartY;  
  124.                 mTouchStartY =mTouchCurrY= y;  
  125.                 invalidate();  
  126.                 break;  
  127.             case MotionEvent.ACTION_MOVE:  
  128.                 mTouchCurrY = y;  
  129.                 invalidate();  
  130.                 break;  
  131.             case MotionEvent.ACTION_UP:  
  132.                 Log.v("Lyric content", middleContent.length()+"");  
  133.                 CharSequence chars = new  CharSequence(){  
  134.   
  135.                     @Override  
  136.                     public char charAt(int index) {  
  137.                         // TODO Auto-generated method stub  
  138.                         return middleContent.charAt(index);  
  139.                     }  
  140.   
  141.                     @Override  
  142.                     public int length() {  
  143.                         // TODO Auto-generated method stub  
  144.                         return middleContent.length();  
  145.                     }  
  146.   
  147.                     @Override  
  148.                     public CharSequence subSequence(int start, int end) {  
  149.                         // TODO Auto-generated method stub  
  150.                         return middleContent.subSequence(start, end);  
  151.                     }  
  152.                     @Override  
  153.                     public String toString(){  
  154.                         return middleContent;  
  155.                     }  
  156.                 };  
  157.                 Toast toast = Toast.makeText(SampleView.this.getContext(),chars, 1000);  
  158.                 toast.show();  
  159.                 invalidate();  
  160.                 break;  
  161.             }  
  162.             return true;  
  163.         }  
  164.   
  165.   
  166.         public void updateIndex(long time) {  
  167.             this.currentTime = time;  
  168.             index = mLyric.getNowSentenceIndex(time);  
  169.             Sentence sen = list.get(index);  
  170.             currentDunringTime = sen.getDuring();  
  171.             sentenctTime  = sen.getFromTime();  
  172.         }  
  173.     } 




Android 实现歌词同步 

歌词同步的原理其实很简单:
  歌词显示是一个线程, 音乐播放时一个线程,通过播放时间将歌词显示进度与播放进度同步起来。
  网络标准的歌词格式是LRC. 我们看下一个LRC文档,其格式就一目了然了.
  [ti:爱]
  [ar:小虎队]
  [al:华纳国语情浓13首]
  [by:爱上你了音乐网]
  [02:08.00][00:38.00]把你的心、我的心串一串
  [02:11.00][00:41.00]串一株幸运草、串一?同心圆
  [02:16.00][00:46.00]让所有期待未?的呼唤
  [02:19.00][00:49.00]趁青春做?伴
  [03:16.00][02:24.00][00:53.00]?让年轻越长大越孤单
  [03:19.00][02:27.00][00:56.00]把我的幸运草种在你的梦田
  [03:23.00][02:31.00][01:01.00]让地球随我?的同心圆
  ….
  LRC 格式为 [歌词显示起始时间][歌词显示结束时间]歌词内容。
  了解歌词同步原理,我们可以想到要做如下工作:
  1. LRC 解析
  2. LRC 歌词显示
  3. 歌词与播放音乐同步
  4. 歌词的获取
  一 LRC解析
  这边我推荐YOYOPlayer 音乐播放开源项目. 源代码已经非常好的支持了LRC解析. 我拿过来就用了.
  过程大概如此: 把LRC文件读到内存里面,用 sentence数据结构存放. Sentence里面有 Fromtime, Totime, content三个成员变量。显示的时候需要这些数据。
  二. LRC歌词显示
  歌词的绘制通过重写 OnDraw方法.
  绘制的代码贴出来:
  long t = tempTime;
  int index = getNowSentenceIndex(t);
  if (index == -1) {
  return;
  }
  Sentence now = list.get(index);
  float f = (t - now.getFromTime()) * 1.0f
  / (now.getToTime() - now.getFromTime());
  if (f > 0.98f) {
  f = 0.98f;
  }
  Shader shader = new LinearGradient(0, 0,
  now.getContentWidth(mTxtPaint), 0, new int[] { Color.RED,
  Color.BLUE }, new float[] { f, f + 0.01f },
  TileMode.CLAMP);
  mTxtPaint.setShader(shader);
  canvas.drawText(now.getContent(), 0, 20, mTxtPaint);
上面的代码很简单,关键一个函数是getNowSentenceIndex(t). 通过播放时间来获得歌词的索引. 我们看下getNowSentenceIndex()如何实现.
  /**
  * 得到当前正在播放的那一句的下标 不可能找不到,因为最开头要加一句 自己的句子 ,所以加了以后就不可能找不到了
  *
  * @return 下标
  */
  private int getNowSentenceIndex(long t) {
  for (int i = 0; i < list.size(); i++) {
  if (list.get(i).isInTime(t)) {
  return i;
  }
  }
  // throw new RuntimeException("竟然出现了找不到的情况!");
  return -1;
  }
  还有一个歌词渐变的效果,其关键代码在与对画笔的设置,如下.
  Shader shader = new LinearGradient(0, 0,
  now.getContentWidth(mTxtPaint), 0, new int[] { Color.RED,
  Color.BLUE }, new float[] { f, f + 0.01f },
  TileMode.CLAMP);
  mTxtPaint.setShader(shader);
  三. 歌词与播放音乐同步
  音乐播放的时候,同时启动歌词显示线程. 将音乐播放的时间设置到歌词View的成员变量中, 以达到同步的目的。
  private class MyHandler extends Handler {
  @Override
  public void handleMessage(Message msg) {
  // Log.v("#################hahah", "" + mp.getCurrentPosition());
  // 重画
  lrcView.mLyric.setTime(mp.getCurrentPosition());
  lrcView.invalidate();
  }
  }
  四. 歌词的获取
  歌词的获取是通过百度搜索出来的. 具体代码如下,很好看懂,关键代码如下:
  GetMethod get = new GetMethod("http://www.baidu.com/s?wd=" + URLEncoder.encode("filetype:lrc " + key, "GBK"));
  get.addRequestHeader("Host", "www.baidu.com");
  get.addRequestHeader("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11");
  get.addRequestHeader("Accept", "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5");
  get.addRequestHeader("Accept-Language", "zh-cn,zh;q=0.5");
  get.addRequestHeader("Keep-Alive", "300");
  get.addRequestHeader("Referer", "http://www.baidu.com/");
  get.addRequestHeader("Connection", "keep-alive");
  int i = http.executeMethod(get);

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值