Android仿天天动听歌曲自动滚动view

Android仿天天动听歌曲自动滚动view,第1张

概述最近项目中要做一个类似天天动听歌曲自动滚动行数的效果。首先自己想了下Android要滚动的那就是scroller类或者scrollto、scrollby结合了,或者view.layout()方法,或者使用动画。但是要循环滚动,貌似这些到最后一

最近项目中要做一个类似天天动听歌曲自动滚动行数的效果。首先自己想了下AndroID要滚动的那就是scroller类或者scrollto、scrollby结合了,或者vIEw.layout()方法,或者使用动画。但是要循环滚动,貌似这些到最后一行滚动到第一行都有往回滚的效果,都不是很好的解决方法。怎么会忘记了可以绘制事件万物的的canvas呢。好吧,既然找到了,那就用这个方案吧!但是天天动听歌曲还有一个手动滑动的效果,貌似这篇文章没写。既然这样,那就自己来写下吧!实现之前还是先看下天天动听的效果:

正文

想法1:获取滑动的距离,然后计算滑动了多少行,然后更新数据。实现起来貌似效果不咋地。
想法2:我们可以看的出来他滚动是一行一行的滚动的,只是根据滚动的快慢来决定滚动行数的快慢。既然这样的话,只要滚动了,就一定时间的去一行行的滚动,然后根据滚动的速度来决定更新的间隔时间。

嗯,想好了怎么实现,现在就来写代码吧。

先来写一个类,继承TextVIEw

VerticalScrollTextVIEw.class

public class VerticalScrollTextVIEw extends TextVIEw implements Runnable{ //绘制歌词画笔 private Paint mContentPaint; //绘制基线画笔 private Paint mlinePaint; //绘制滑动进度背景画笔 private Paint mRectPaint; //歌词数据 private List<Sentence> mDataList; //行数 private int index = 0 ; //当前vIEw的宽 private float mX; //当前vIEw的高 private float mY; //当前vIEw垂直方向中线 private float mIDdleY; //行与行之间的间距 private final static int DY = 80 ; //歌词文字大小 private int mTextSize = 35; //歌词中间字体的大小 private int mBigTextSize = 45; //当前是否按下 private boolean istouch = false ; //上一次触摸vIEw的y轴坐标 private float mLastY; //是否正在滑动 private boolean isMoving; //记录上一次滑动的时间 private long lastMoveTime; //滑动速度追踪类 private VeLocityTracker mVeLocityTracker; //滑动最大速度 private int mMaximumVeLocity; //歌词是否为空 private boolean isEmpty; public VerticalScrollTextVIEw(Context context) { this(context,null); } public VerticalScrollTextVIEw(Context context,AttributeSet attrs) { this(context,attrs,0); } public VerticalScrollTextVIEw(Context context,AttributeSet attrs,int defStyleAttr) { super(context,defStyleAttr); //获取最大的滑动速度值 mMaximumVeLocity = VIEwConfiguration.get(context)  .getScaledMaximumFlingVeLocity(); init(); } private voID init(){ setFocusable(true); setClickable(true); //歌词为空设置默认值 if(mDataList==null){  mDataList = new ArrayList<>();  Sentence sentence = new Sentence(0,"没有获取到歌词",0);  mDataList.add(sentence);  isEmpty = true ; } //初始化歌词画笔 mContentPaint = new Paint(); mContentPaint.setTextSize(mTextSize); mContentPaint.setAntiAlias(true); mContentPaint.setcolor(color.parsecolor("#e5e2e2")); //设置为serif字体 mContentPaint.setTypeface(Typeface.serif); //设置字体为居中 mContentPaint.setTextAlign(Paint.Align.CENTER); //初始化基线画笔 mlinePaint = new Paint(); mlinePaint.setAntiAlias(true); mlinePaint.setstrokeWIDth(1); mlinePaint.setcolor(color.WHITE); //进度背景颜色画笔 mRectPaint = new Paint(); mlinePaint.setAntiAlias(true); mRectPaint.setcolor(color.parsecolor("#66666666")); } @OverrIDe protected voID onDraw(Canvas canvas) { super.onDraw(canvas); //如果当前进度为-1,直接返回,不用绘制 if (index == -1)  return; Sentence sentence = mDataList.get(index); //绘制中间行的歌词,设置为高亮白色,大字体 mContentPaint.setcolor(color.WHITE); mContentPaint.setTextSize(mBigTextSize); canvas.drawText(sentence.getname(),mX/2,mIDdleY,mContentPaint); //当前为歌词不为空并且按下的情况下,绘制基线和进度 if(!isEmpty&&istouch){  //获取中间行字体最高的位置  float baseline = mIDdleY-Math.abs(mContentPaint.ascent());  //绘制进度背景  canvas.drawRect(10.0f,baseline-70,150.0f,baseline,mRectPaint);  //绘制基线  canvas.drawline(10.0f,mX-10,mlinePaint);  //设置进度字体大小  mContentPaint.setTextSize(mTextSize);  //绘制进度字体  canvas.drawText(String.valueOf(index),85,baseline-35,mContentPaint); } //初始化isEmpty isEmpty = false ; //初始化歌词内容画笔 mContentPaint.setcolor(color.parsecolor("#e5e2e2")); mContentPaint.setTextSize(mTextSize); //暂时保存中间线位置,来绘制中间线以上的行数字体 float tempY = mIDdleY; //绘制中间线以上的歌词 for (int i = index - 1; i >= 0; i--) {  tempY = tempY - DY;  if (tempY < 0) {  break;  }  Sentence preSentence = mDataList.get(i);  canvas.drawText(preSentence.getname(),tempY,mContentPaint); } tempY = mIDdleY; //绘制中间线以下的歌词 for (int i = index + 1; i < mDataList.size(); i++) {  tempY = tempY + DY;  if (tempY > mY) {  break;  }  Sentence nexeSentence = mDataList.get(i);  canvas.drawText(nexeSentence.getname(),mContentPaint); } //初始化isMoving,到这里表示滑动结束 isMoving = false ; } protected voID onSizeChanged(int w,int h,int ow,int oh) { super.onSizeChanged(w,h,ow,oh); //获取vIEw的宽和高 mX = w; mY = h; mIDdleY = h * 0.5f; } public long updateIndex(int index) { if (index == -1)  return -1; this.index=index; return index; } public List<Sentence> getDataList() { return mDataList; } public voID setDataList(List<Sentence> mDataList){ this.mDataList = mDataList ; } public voID updateUI(){ new Thread(this).start(); } @OverrIDe public boolean ontouchEvent(MotionEvent event) { int action = event.getAction(); switch (action){  case MotionEvent.ACTION_DOWN:  istouch =true;  mLastY = event.getY();  break;  case MotionEvent.ACTION_MOVE:  //创建速度追踪器  initVeLocityTrackerIfNotExists();  mVeLocityTracker.addMovement(event);  mVeLocityTracker.computeCurrentVeLocity(1000,mMaximumVeLocity);  //获取当前速度。默认为100  float veLocity = mVeLocityTracker.getYVeLocity()==0?100:mVeLocityTracker.getYVeLocity();  long currentTime = System.currentTimeMillis();  //设置一个固定值和速度结合决定滑动更新的快慢  if(!isMoving&¤tTime-lastMoveTime>20000/Math.abs(veLocity)){   isMoving = true ;   lastMoveTime = System.currentTimeMillis();   float currentY = event.getY();   float mMoveY = currentY - mLastY;   //向上滑动-1向下滑动+1   int newIndex = mMoveY>0?index - 1:index+1;   //循环滚动   newIndex=newIndex<0?mDataList.size()-1:newIndex>=mDataList.size()?0:newIndex;   updateIndex(newIndex);   invalIDate();   mLastY = currentY;  }  break;  case MotionEvent.ACTION_UP:  istouch = false ;  recycleVeLocityTracker();  break; } return super.ontouchEvent(event); } @OverrIDe public voID run() { //自动滚动刷新的时间间隔 long time = 1000; //控制进度 int i=0; while (true) {  //当前不在按下的情况下自动滚动  if(!istouch){  //设置当前的进度值  long sleeptime = updateIndex(i);  //使用handle刷新ui  mHandler.post(mUpdateResults);  if (sleeptime == -1)   return;  try {   Thread.sleep(time);   i++;   //当到了最后一行的时候自动跳转到第一行   if(i==getDataList().size())   i=0;  } catch (InterruptedException e) {   e.printstacktrace();  }  } } } Handler mHandler = new Handler(); Runnable mUpdateResults = new Runnable() { public voID run() {  invalIDate(); } }; //创建速度追踪器 private voID initVeLocityTrackerIfNotExists() { if (mVeLocityTracker == null) {  mVeLocityTracker = VeLocityTracker.obtain(); } } //释放 private voID recycleVeLocityTracker() { if (mVeLocityTracker != null) {  mVeLocityTracker.recycle();  mVeLocityTracker = null; } }}

自定义view基本就是这样了,我们可以把要定义的一些属性写在attrs里面了,这里就懒得写了。大概的思路就是先绘制指定的index行的歌词,然后绘制index上面行的歌词,然后绘制index下面行的歌词。然后新建一个线程,让它通过handle隔一定的时间定时刷新歌词行数。然后在ontouchEvent处理触摸滚动行数,获取到当前滚动速度来决定一个更新的时间间隔。从而实现触摸滚动刷新的快慢。基本上就是这样了。其他的看注释。

再看下初始化数据测试的Activity:

VerticalScrollTextActivity.class

public class VerticalScrollTextActivity extends Activity { VerticalScrollTextVIEw mSampleVIEw; String[] str = {"你在南方的艳阳里 大雪纷飞","我在北方的寒夜里 四季如春","如果天黑之前来的及","我要忘了你的眼睛","穷极一生 做不完一场梦","他不在和谁谈论相逢的孤岛","因为心里早已荒无人烟","他的心里在装不下一个家","做一个只对自己说谎的哑巴","他说你任何为人称道的美丽","不及他第一次遇见你","时光苟延残喘 无可奈何","如果所有土地连在一起","走上一生只为拥抱你","喝醉了他的梦 晚安","你在南方的艳阳里 大雪纷飞","喝醉了他的梦 晚安" }; @OverrIDe public voID onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentVIEw(R.layout.activity_main); mSampleVIEw = (VerticalScrollTextVIEw) findVIEwByID(R.ID.sampleVIEw1); List lst=new ArrayList<>(); for(int i=0;i<str.length;i++){  Sentence sen=new Sentence(i,str[i],i+1202034);  lst.add(i,sen); } mSampleVIEw.setDataList(lst); mSampleVIEw.updateUI(); } }

模拟了一首歌词数据,然后setDataList,在调用updateUI()就行了。

最后看下布局文件

activity_main.xml

<?xml version="1.0" enCoding="utf-8"?><relativeLayout xmlns:androID="http://schemas.androID.com/apk/res/androID" androID:layout_wIDth="match_parent" androID:layout_height="match_parent"> <com.goach.lib.VerticalScrollTextVIEw androID:ID="@+ID/sampleVIEw1" androID:layout_wIDth="match_parent" androID:layout_height="match_parent" androID:background="@drawable/bg" /></relativeLayout>

测试下,我们就可以看到效果了:

 

源码下载:Android仿天天动听歌曲自动滚动

以上就是本文的全部内容,希望对大家学习AndroID软件编程有所帮助。

总结

以上是内存溢出为你收集整理的Android仿天天动听歌曲自动滚动view全部内容,希望文章能够帮你解决Android仿天天动听歌曲自动滚动view所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1141713.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存