最近项目中要做一个类似天天动听歌曲自动滚动行数的效果。首先自己想了下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所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)