
正文
想法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, attrs, 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,baseLine,mX-10,baseLine,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(), mX/2, 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(), mX/2, tempY, 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);//获取当前速度。默认为100float 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刷新uimHandler.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; } }}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()就行了。<?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软件编程有所帮助。