java歌词同步显示软件下载_YOYOPlayer开发手记(四)歌词同步显示

/** To change this template, choose Tools | Templates

* and open the template in the editor.*/packagecom.hadeslee.yoyoplayer.lyric;importcom.hadeslee.yoyoplayer.playlist.PlayListItem;importcom.hadeslee.yoyoplayer.util.Config;importcom.hadeslee.yoyoplayer.util.Util;importjava.awt.Color;importjava.awt.Graphics;importjava.awt.Graphics2D;importjava.awt.LinearGradientPaint;importjava.io.BufferedReader;importjava.io.BufferedWriter;importjava.io.File;importjava.io.FileFilter;importjava.io.FileInputStream;importjava.io.FileOutputStream;importjava.io.IOException;importjava.io.InputStreamReader;importjava.io.OutputStreamWriter;importjava.io.Serializable;importjava.io.StringReader;importjava.util.ArrayList;importjava.util.Collections;importjava.util.Comparator;importjava.util.List;importjava.util.logging.Level;importjava.util.logging.Logger;importjava.util.regex.Matcher;importjava.util.regex.Pattern;/*** 表示一首歌的歌词对象,它可以以某种方式来画自己

*@authorhadeslee*/publicclassLyricimplementsSerializable {privatestaticfinallongserialVersionUID=20071125L;privatestaticLogger log=Logger.getLogger(Lyric.class.getName());privateintwidth;//表示歌词的显示区域的宽度privateintheight;//表示歌词的显示区域的高度privatelongtime;//表示当前的时间是多少了。以毫秒为单位privatelongtempTime;//表示一个暂时的时间,用于拖动的时候,确定应该到哪了privateListlist=newArrayList();//里面装的是所有的句子privatebooleanisMoving;//是否正在被拖动privateintcurrentIndex;//当前正在显示的歌词的下标privatebooleaninitDone;//是否初始化完毕了privatetransientPlayListItem info;//有关于这首歌的信息privatetransientFile file;//该歌词所存在文件privatebooleanenabled=true;//是否起用了该对象,默认是起用的privatelongduring=Integer.MAX_VALUE;//这首歌的长度/*** 用ID3V1标签的字节和歌名来初始化歌词

* 歌词将自动在本地或者网络上搜索相关的歌词并建立关联

* 本地搜索将硬编码为user.home文件夹下面的Lyrics文件夹

* 以后改为可以手动设置.

*@paramsongName 歌名

*@paramdata ID3V1的数据*/publicLyric(finalPlayListItem info) {this.info=info;this.during=info.getLength()*1000;this.file=info.getLyricFile();

log.info("传进来的歌名是:"+info.toString());//只要有关联好了的,就不用搜索了直接用就是了if(file!=null) {

log.log(Level.INFO,"不用找了,直接关联到的歌词是:"+file);

init(file);

initDone=true;return;

}else{//否则就起一个线程去找了,先是本地找,然后再是网络上找newThread() {publicvoidrun() {

doInit(info);

initDone=true;

}

}.start();

}

}/*** 读取某个指定的歌词文件,这个构造函数一般用于

* 拖放歌词文件到歌词窗口时调用的,拖放以后,两个自动关联

*@paramfile 歌词文件

*@paraminfo 歌曲信息*/publicLyric(File file, PlayListItem info) {this.file=file;this.info=info;

init(file);

initDone=true;

}/*** 根据歌词内容和播放项构造一个

* 歌词对象

*@paramlyric 歌词内容

*@paraminfo 播放项*/publicLyric(String lyric, PlayListItem info) {this.info=info;this.init(lyric);

initDone=true;

}privatevoiddoInit(PlayListItem info) {

init(info);

Sentence temp=null;//这个时候就要去网络上找了if(list.size()==1) {

temp=list.remove(0);try{

String lyric=Util.getLyric(info);if(lyric!=null) {

init(lyric);

saveLyric(lyric, info);

}else{//如果网络也没有找到,就要加回去了list.add(temp);

}

}catch(IOException ex) {

Logger.getLogger(Lyric.class.getName()).log(Level.SEVERE,null, ex);//如果抛了任何异常,也要加回去了list.add(temp);

}

}

}/*** 把下载到的歌词保存起来,免得下次再去找

*@paramlyric 歌词内容

*@paraminfo 歌的信息*/privatevoidsaveLyric(String lyric, PlayListItem info) {try{//如果歌手不为空,则以歌手名+歌曲名为最好组合String name=info.getFormattedName()+".lrc";//File dir = new File(Config.HOME, "Lyrics" + File.separator);File dir=Config.getConfig().getSaveLyricDir();

dir.mkdirs();

file=newFile(dir, name);

BufferedWriter bw=newBufferedWriter(newOutputStreamWriter(newFileOutputStream(file),"GBK"));

bw.write(lyric);

bw.close();

info.setLyricFile(file);

log.info("保存完毕,保存在:"+file);

}catch(Exception exe) {

log.log(Level.SEVERE,"保存歌词出错", exe);

}

}/*** 设置此歌词是否起用了,否则就不动了

*@paramb 是否起用*/publicvoidsetEnabled(booleanb) {this.enabled=b;

}/*** 得到此歌词保存的地方

*@return文件*/publicFile getLyricFile() {returnfile;

}/*** 调整整体的时间,比如歌词统一快多少

* 或者歌词统一慢多少,为正说明要快,为负说明要慢

*@paramtime 要调的时间,单位是毫秒*/publicvoidadjustTime(inttime) {//如果是只有一个显示的,那就说明没有什么效对的意义了,直接返回if(list.size()==1) {return;

}for(Sentence s : list) {

s.setFromTime(s.getFromTime()-time);

s.setToTime(s.getToTime()-time);

}

}/*** 根据一个文件夹,和一个歌曲的信息

* 从本地搜到最匹配的歌词

*@paramdir 目录

*@paraminfo 歌曲信息

*@return歌词文件*/privateFile getMathedLyricFile(File dir, PlayListItem info) {

File matched=null;//已经匹配的文件File[] fs=dir.listFiles(newFileFilter() {publicbooleanaccept(File pathname) {returnpathname.getName().toLowerCase().endsWith(".lrc");

}

});for(File f : fs) {//全部匹配或者部分匹配都行if(matchAll(info, f)||matchSongName(info, f)) {

matched=f;break;

}

}returnmatched;

}/*** 根据歌的信息去初始化,这个时候

* 可能在本地找到歌词文件,也可能要去网络上搜索了

*@paraminfo 歌曲信息*/privatevoidinit(PlayListItem info) {

File matched=null;for(File dir : Config.getConfig().getSearchLyricDirs()) {

log.log(Level.FINE,"正在搜索文件夹:"+dir);//得到歌曲信息后,先本地搜索,先搜索HOME文件夹//如果还不存在的话,那建一个目录,然后直接退出不管了if(!dir.exists()) {

dir.mkdirs();

}

matched=getMathedLyricFile(dir, info);//当搜索到了,就退出if(matched!=null) {break;

}

}

log.info("找到的是:"+matched);if(matched!=null) {

info.setLyricFile(matched);

file=matched;

init(matched);

}else{

init("");

}

}/*** 根据文件来初始化

*@paramfile 文件*/privatevoidinit(File file) {

BufferedReader br=null;try{

br=newBufferedReader(newInputStreamReader(newFileInputStream(file),"GBK"));

StringBuilder sb=newStringBuilder();

String temp=null;while((temp=br.readLine())!=null) {

sb.append(temp).append("\n");

}

init(sb.toString());

}catch(Exception ex) {

Logger.getLogger(Lyric.class.getName()).log(Level.SEVERE,null, ex);

}finally{try{

br.close();

}catch(Exception ex) {

Logger.getLogger(Lyric.class.getName()).log(Level.SEVERE,null, ex);

}

}

}/*** 是否完全匹配,完全匹配是指直接对应到ID3V1的标签,

* 如果一样,则完全匹配了,完全匹配的LRC的文件格式是:

* 阿木 - 有一种爱叫放手.lrc

*@paraminfo 歌曲信息

*@paramfile 侯选文件

*@return是否合格*/privatebooleanmatchAll(PlayListItem info, File file) {

String name=info.getFormattedName();

String fn=file.getName().substring(0, file.getName().lastIndexOf("."));if(name.equals(fn)) {returntrue;

}else{returnfalse;

}

}/*** 是否匹配了歌曲名

*@paraminfo 歌曲信息

*@paramfile 侯选文件

*@return是否合格*/privatebooleanmatchSongName(PlayListItem info, File file) {

String name=info.getFormattedName();

String rn=file.getName().substring(0, file.getName().lastIndexOf("."));if(name.equalsIgnoreCase(rn)||info.getTitle().equalsIgnoreCase(rn)) {returntrue;

}else{returnfalse;

}

}/*** 最重要的一个方法,它根据读到的歌词内容

* 进行初始化,比如把歌词一句一句分开并计算好时间

*@paramcontent 歌词内容*/privatevoidinit(String content) {//如果歌词的内容为空,则后面就不用执行了//直接显示歌曲名就可以了if(content==null||content.trim().equals("")) {

list.add(newSentence(info.getFormattedName(), Integer.MIN_VALUE, Integer.MAX_VALUE));return;

}try{

BufferedReader br=newBufferedReader(newStringReader(content));

String temp=null;while((temp=br.readLine())!=null) {

parseLine(temp.trim());

}

br.close();//读进来以后就排序了Collections.sort(list,newComparator() {publicintcompare(Sentence o1, Sentence o2) {return(int) (o1.getFromTime()-o2.getFromTime());

}

});//处理第一句歌词的起始情况,无论怎么样,加上歌名做为第一句歌词,并把它的//结尾为真正第一句歌词的开始if(list.size()==0) {

list.add(newSentence(info.getFormattedName(),0, Integer.MAX_VALUE));return;

}else{

Sentence first=list.get(0);

list.add(0,newSentence(info.getFormattedName(),0, first.getFromTime()));

}intsize=list.size();for(inti=0; i

Sentence next=null;if(i+1

next=list.get(i+1);

}

Sentence now=list.get(i);if(next!=null) {

now.setToTime(next.getFromTime()-1);

}

}//如果就是没有怎么办,那就只显示一句歌名了if(list.size()==1) {

list.get(0).setToTime(Integer.MAX_VALUE);

}else{

Sentence last=list.get(list.size()-1);

last.setToTime(info==null?Integer.MAX_VALUE : info.getLength()*1000+1000);

}

}catch(Exception ex) {

Logger.getLogger(Lyric.class.getName()).log(Level.SEVERE,null, ex);

}

}/*** 分析这一行的内容,根据这内容

* 以及标签的数量生成若干个Sentence对象

*@paramline 这一行*/privatevoidparseLine(String line) {if(line.equals("")) {return;

}

Matcher m=Pattern.compile("(?<=\\[).*?(?=\\])").matcher(line);

Listtemp=newArrayList();intlength=0;while(m.find()) {

String s=m.group();

temp.add(s);

length+=(s.length()+2);

}try{

String content=line.substring(length>line.length()?line.length() : length);if(Config.getConfig().isCutBlankChars()) {

content=content.trim();

}if(content.equals("")) {return;

}for(String s : temp) {longt=parseTime(s);if(t!=-1) {

list.add(newSentence(content, t));

}

}

}catch(Exception exe) {

}

}/*** 把如00:00.00这样的字符串转化成

* 毫秒数的时间,比如

* 01:10.34就是一分钟加上10秒再加上340毫秒

* 也就是返回70340毫秒

*@paramtime 字符串的时间

*@return此时间表示的毫秒*/privatelongparseTime(String time) {

String[] ss=time.split("\\:|\\.");//如果 是两位以后,就非法了if(ss.length<2) {return-1;

}elseif(ss.length==2) {//如果正好两位,就算分秒try{intmin=Integer.parseInt(ss[0]);intsec=Integer.parseInt(ss[1]);if(min<0||sec<0||sec>=60) {thrownewRuntimeException("数字不合法!");

}return(min*60+sec)*1000L;

}catch(Exception exe) {return-1;

}

}elseif(ss.length==3) {//如果正好三位,就算分秒,十毫秒try{intmin=Integer.parseInt(ss[0]);intsec=Integer.parseInt(ss[1]);intmm=Integer.parseInt(ss[2]);if(min<0||sec<0||sec>=60||mm<0||mm>99) {thrownewRuntimeException("数字不合法!");

}return(min*60+sec)*1000L+mm*10;

}catch(Exception exe) {return-1;

}

}else{//否则也非法return-1;

}

}/*** 设置其显示区域的高度

*@paramheight 高度*/publicvoidsetHeight(intheight) {this.height=height;

}/*** 设置其显示区域的宽度

*@paramwidth 宽度*/publicvoidsetWidth(intwidth) {this.width=width;

}/*** 设置时间

*@paramtime 时间*/publicvoidsetTime(longtime) {if(!isMoving) {

tempTime=this.time=time;

}

}/*** 得到是否初始化完成了

*@return是否完成*/publicbooleanisInitDone() {returninitDone;

}privatevoiddrawKaraoke(Graphics2D gd, Sentence now,intx,inty,longt) {intnowWidth=now.getContentWidth(gd);

Color gradient=null;//如果要渐入渐出才去求中间色,否则直接用高亮色画if(Config.getConfig().isLyricShadow()) {

gradient=now.getBestInColor(Config.getConfig().getLyricHilight(), Config.getConfig().getLyricForeground(), t);

}else{

gradient=Config.getConfig().getLyricHilight();

}if(Config.getConfig().isKaraoke()) {floatf=(t-now.getFromTime())*1.0f/(now.getToTime()-now.getFromTime());if(f>0.98f) {

f=0.98f;

}if(x==0) {

x=1;

}if(nowWidth==0) {

nowWidth=1;

}

gd.setPaint(newLinearGradientPaint(x, y, x+nowWidth, y,newfloat[]{f, f+0.01f},newColor[]{gradient, Config.getConfig().getLyricForeground()}));

}else{

gd.setPaint(gradient);

}

Util.drawString(gd, now.getContent(), x, y);

}/*** 自力更生,画出自己在水平方向的方法

* 这个做是为了更方便地把歌词显示在

* 任何想显示的地方

*@paramg 画笔*/publicsynchronizedvoiddrawH(Graphics g) {if(!enabled) {

Sentence sen=newSentence(info.getFormattedName());intx=(width-sen.getContentWidth(g))/2;inty=(height-sen.getContentHeight(g)+Config.getConfig().getV_SPACE())/2;

g.setColor(Config.getConfig().getLyricHilight());

Util.drawString(g, sen.getContent(), x, y);return;

}//首先看是不是初始化完毕了if(!initDone) {

Sentence temp=newSentence("正在搜索歌词");intx=(width-temp.getContentWidth(g))/2;inty=(height-temp.getContentHeight(g))/2;

g.setColor(Config.getConfig().getLyricHilight());

Util.drawString(g, temp.getContent(), x, y);return;

}//如果只存在一句的话,那就不要浪费那么多计算的时候了//直接画在中间就可以了if(list.size()==1) {

Sentence sen=list.get(0);intx=(width-sen.getContentWidth(g))/2;inty=(height-sen.getContentHeight(g)+Config.getConfig().getV_SPACE())/2;

g.setColor(Config.getConfig().getLyricHilight());

Util.drawString(g, sen.getContent(), x, y);

}else{//取一个time的副本,以防止在一个方法里面产生两种time的情况longt=tempTime;

Graphics2D gd=(Graphics2D) g;intindex=getNowSentenceIndex(t);if(!isMoving) {

currentIndex=index;

}if(index==-1) {

Sentence sen=newSentence(info.getFormattedName(), Integer.MIN_VALUE, Integer.MAX_VALUE);intx=(width-sen.getContentWidth(g)-Config.getConfig().getH_SPACE())/2;inty=(height-sen.getContentHeight(g)+Config.getConfig().getV_SPACE())/2;

g.setColor(Config.getConfig().getLyricHilight());

Util.drawString(g, sen.getContent(), x, y);return;

}

Sentence now=list.get(index);intnowWidth=now.getContentWidth(g)+Config.getConfig().getH_SPACE();intx=(width)/2-now.getHIncrease(g, t);inty=(height-now.getContentHeight(g))/2;this.drawKaraoke(gd, now, x, y, t);

gd.setPaint(Config.getConfig().getLyricForeground());inttempX=x;//画出中间那句之前的句子for(inti=index-1; i>=0; i--) {

Sentence sen=list.get(i);intwid=sen.getContentWidth(g)+Config.getConfig().getH_SPACE();

tempX=tempX-wid;if(tempX+wid<0) {break;

}if(Config.getConfig().isLyricShadow()) {if(i==index-1) {

gd.setPaint(sen.getBestOutColor(Config.getConfig().getLyricHilight(),

Config.getConfig().getLyricForeground(), time));

}else{

gd.setPaint(Config.getConfig().getLyricForeground());

}

}

Util.drawString(g, sen.getContent(), tempX, y);

}

gd.setPaint(Config.getConfig().getLyricForeground());

tempX=x;inttempWidth=nowWidth;//画出中间那句之后的句子for(inti=index+1; i

Sentence sen=list.get(i);

tempX=tempX+tempWidth;if(tempX>width) {break;

}

Util.drawString(g, sen.getContent(), tempX, y);

tempWidth=sen.getContentWidth(g)+Config.getConfig().getH_SPACE();

}

}

}/*** 得到这批歌词里面,最长的那一句的长度

*@return最长的长度*/publicintgetMaxWidth(Graphics g) {intmax=0;for(Sentence sen : list) {intw=sen.getContentWidth(g);if(w>max) {

max=w;

}

}returnmax;

}/*** 得到一句话的X座标,因为可能对齐方式有

* 多种,针对每种对齐方式,X的座标不一

* 定一样。

*@paramg 画笔

*@paramsen 要求的句子

*@return本句的X座标*/privateintgetSentenceX(Graphics g, Sentence sen) {intx=0;inti=Config.getConfig().getLyricAlignMode();switch(i) {caseConfig.LYRIC_CENTER_ALIGN:

x=(width-sen.getContentWidth(g))/2;break;caseConfig.LYRIC_LEFT_ALIGN:

x=0;break;caseConfig.LYRIC_RIGHT_ALIGN:

x=width-sen.getContentWidth(g);break;default://默认情况还是中间对齐x=(width-sen.getContentWidth(g))/2;break;

}returnx;

}/*** 画出自己在垂直方向上的过程

*@paramg 画笔*/publicsynchronizedvoiddrawV(Graphics g) {if(!enabled) {

Sentence sen=newSentence(info.getFormattedName());intx=(width-sen.getContentWidth(g))/2;inty=(height-sen.getContentHeight(g)+Config.getConfig().getV_SPACE())/2;

g.setColor(Config.getConfig().getLyricHilight());

Util.drawString(g, sen.getContent(), x, y);return;

}//首先看是不是初始化完毕了if(!initDone) {

Sentence temp=newSentence("正在搜索歌词");intx=getSentenceX(g, temp);inty=(height-temp.getContentHeight(g))/2;

g.setColor(Config.getConfig().getLyricHilight());

Util.drawString(g, temp.getContent(), x, y);return;

}//如果只存在一句的话,那就不要浪费那么多计算的时候了//直接画在中间就可以了if(list.size()==1) {

Sentence sen=list.get(0);intx=getSentenceX(g, sen);inty=(height-sen.getContentHeight(g))/2;

g.setColor(Config.getConfig().getLyricHilight());

Util.drawString(g, sen.getContent(), x, y);

}else{longt=tempTime;

Graphics2D gd=(Graphics2D) g;intindex=getNowSentenceIndex(t);if(!isMoving) {

currentIndex=index;

}if(index==-1) {

Sentence sen=newSentence(info.getFormattedName(), Integer.MIN_VALUE, Integer.MAX_VALUE);intx=getSentenceX(g, sen);inty=(height-sen.getContentHeight(g))/2;

gd.setPaint(Config.getConfig().getLyricHilight());

Util.drawString(g, sen.getContent(), x, y);return;

}

Sentence now=list.get(index);//先求出中间的最基准的纵座标inty=(height+now.getContentHeight(g))/2-now.getVIncrease(g, t);intx=getSentenceX(g, now);this.drawKaraoke(gd, now, x, y, t);

gd.setColor(Config.getConfig().getLyricForeground());//然后再画上面的部份以及下面的部份//这样就可以保证正在唱的歌词永远在正中间显示inttempY=y;//画出本句之前的句子for(inti=index-1; i>=0; i--) {

Sentence sen=list.get(i);intx1=getSentenceX(g, sen);

tempY=tempY-sen.getContentHeight(g)-Config.getConfig().getV_SPACE();if(tempY+sen.getContentHeight(g)<0) {break;

}if(Config.getConfig().isLyricShadow()) {if(i==index-1) {

gd.setColor(sen.getBestOutColor(Config.getConfig().getLyricHilight(),

Config.getConfig().getLyricForeground(), time));

}else{

gd.setColor(Config.getConfig().getLyricForeground());

}

}

Util.drawString(g, sen.getContent(), x1, tempY);

}

gd.setColor(Config.getConfig().getLyricForeground());

tempY=y;//画出本句之后的句子for(inti=index+1; i

Sentence sen=list.get(i);intx1=getSentenceX(g, sen);

tempY=tempY+sen.getContentHeight(g)+Config.getConfig().getV_SPACE();if(tempY>height) {break;

}

Util.drawString(g, sen.getContent(), x1, tempY);

}

}

}/*** 得到当前正在播放的那一句的下标

* 不可能找不到,因为最开头要加一句

* 自己的句子 ,所以加了以后就不可能找不到了

*@return下标*/privateintgetNowSentenceIndex(longt) {for(inti=0; i

}

}//throw new RuntimeException("竟然出现了找不到的情况!");return-1;

}/*** 水平移动多少个象素,这个方法是给面板调用的

* 移动了这些象素以后,要马上算出这个象素所

* 对应的时间是多少,要注意时间超出的情况

*@paramlength

*@paramg 画笔,因为对于每一个画笔长度不一样的*/publicvoidmoveH(intlength, Graphics g) {if(list.size()==1||!enabled) {return;

}//如果长度是大于0的,则说明是正向移动,快进if(length>0) {

Sentence now=list.get(currentIndex);intnowWidth=now.getContentWidth(g);floatf=(time-now.getFromTime())*1.0f/(now.getToTime()-now.getFromTime());//先算出当前的这一句还剩多少长度了intrest=(int) ((1-f)*nowWidth);longtimeAdd=0;//要加多少时间//如果剩下的长度足够了,那是最好,马上就可以返回了if(rest>length) {

timeAdd=now.getTimeH(length, g);

}else{

timeAdd=now.getTimeH(rest, g);for(inti=currentIndex; i

Sentence sen=list.get(i);intlen=sen.getContentWidth(g);//如果加上下一句的长度还不够,就把时间再加,继续下一句if(len+rest

timeAdd+=sen.getDuring();

rest+=len;

}else{

timeAdd+=sen.getTimeH(length-rest, g);break;

}

}

}

tempTime=time+timeAdd;

checkTempTime();

}else{//否则就是反向移动,要快退了length=0-length;//取它的正数Sentence now=list.get(currentIndex);intnowWidth=now.getContentWidth(g);floatf=(time-now.getFromTime())*1.0f/(now.getToTime()-now.getFromTime());//先算出当前的这一句已经用了多少长度了intrest=(int) (f*nowWidth);longtimeAdd=0;//要加多少时间//如果剩下的长度足够了,那是最好,马上就可以返回了if(rest>length) {

timeAdd=now.getTimeH(length, g);

}else{

timeAdd=now.getTimeH(rest, g);for(inti=currentIndex; i>0; i--) {

Sentence sen=list.get(i);intlen=sen.getContentWidth(g);//如果加上下一句的长度还不够,就把时间再加,继续下一句if(len+rest

timeAdd+=sen.getDuring();

rest+=len;

}else{

timeAdd+=sen.getTimeH(length-rest, g);break;

}

}

}

tempTime=time-timeAdd;

checkTempTime();

}

}/*** 竖直移动多少个象素,这个方法是给面板调用的

* 移动了这些象素以后,要马上算出这个象素所

* 对应的时间是多少,要注意时间超出的情况

*@paramlength

*@paramg 画笔,因为对于每一个画笔长度不一样的*/publicvoidmoveV(intlength, Graphics g) {if(list.size()==1||!enabled) {return;

}//如果长度是大于0的,则说明是正向移动,快进if(length>0) {

Sentence now=list.get(currentIndex);intnowHeight=now.getContentHeight(g);floatf=(time-now.getFromTime())*1.0f/(now.getToTime()-now.getFromTime());//先算出当前的这一句还剩多少长度了intrest=(int) ((1-f)*nowHeight);longtimeAdd=0;//要加多少时间//如果剩下的长度足够了,那是最好,马上就可以返回了if(rest>length) {

timeAdd=now.getTimeV(length, g);

}else{

timeAdd=now.getTimeV(rest, g);for(inti=currentIndex; i

Sentence sen=list.get(i);intlen=sen.getContentHeight(g);//如果加上下一句的长度还不够,就把时间再加,继续下一句if(len+rest

timeAdd+=sen.getDuring();

rest+=len;

}else{

timeAdd+=sen.getTimeV(length-rest, g);break;

}

}

}

tempTime=time+timeAdd;

checkTempTime();

}else{//否则就是反向移动,要快退了length=0-length;//取它的正数Sentence now=list.get(currentIndex);intnowHeight=now.getContentHeight(g);floatf=(time-now.getFromTime())*1.0f/(now.getToTime()-now.getFromTime());//先算出当前的这一句已经用了多少长度了intrest=(int) (f*nowHeight);longtimeAdd=0;//要加多少时间//如果剩下的长度足够了,那是最好,马上就可以返回了if(rest>length) {

timeAdd=now.getTimeV(length, g);

}else{

timeAdd=now.getTimeV(rest, g);for(inti=currentIndex; i>0; i--) {

Sentence sen=list.get(i);intlen=sen.getContentHeight(g);//如果加上下一句的长度还不够,就把时间再加,继续下一句if(len+rest

timeAdd+=sen.getDuring();

rest+=len;

}else{

timeAdd+=sen.getTimeV(length-rest, g);break;

}

}

}

tempTime=time-timeAdd;

checkTempTime();

}

}/*** 是否能拖动,只有有歌词才可以被拖动,否则没有意义了

*@return能否拖动*/publicbooleancanMove() {returnlist.size()>1&&enabled;

}/*** 得到当前的时间,一般是由显示面板调用的*/publiclonggetTime() {returntempTime;

}/*** 在对tempTime做了改变之后,检查一下它的

* 值,看是不是在有效的范围之内*/privatevoidcheckTempTime() {if(tempTime<0) {

tempTime=0;

}elseif(tempTime>during) {

tempTime=during;

}

}/*** 告诉歌词,要开始移动了,

* 在此期间,所有对歌词的直接的时间设置都不理会*/publicvoidstartMove() {

isMoving=true;

}/*** 告诉歌词拖动完了,这个时候的时间改

* 变要理会,并做更改*/publicvoidstopMove() {

isMoving=false;

}publicstaticvoidmain(String[] args) {

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值