android高仿天天动听,Android仿天天动听歌曲自动滚动view

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

815f5a07ea228d28b36c451ec4ebd40a.png

正文

想法1:获取滑动的距离,然后计算滑动了多少行,然后更新数据。实现起来貌似效果不咋地。

想法2:我们可以看的出来他滚动是一行一行的滚动的,只是根据滚动的快慢来决定滚动行数的快慢。既然这样的话,只要滚动了,就一定时间的去一行行的滚动,然后根据滚动的速度来决定更新的间隔时间。

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

先来写一个类,继承TextView

VerticalScrollTextView.class

public class VerticalScrollTextView extends TextView implements Runnable{

//绘制歌词画笔

private Paint mContentPaint;

//绘制基线画笔

private Paint mLinePaint;

//绘制滑动进度背景画笔

private Paint mRectPaint;

//歌词数据

private List 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 getDataList() {

return mDataList;

}

public void setDataList(List 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&&currentTime-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

Sentence sen=new Sentence(i,str[i],i+1202034);

lst.add(i, sen);

}

mSampleView.setDataList(lst);

mSampleView.updateUI();

}

}

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

最后看下布局文件

activity_main.xml

android:layout_width="match_parent"

android:layout_height="match_parent">

android:id="@+id/sampleView1"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:background="@drawable/bg"

/>

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

36aad75db16a6d1a9063eebdbc3065fb.gif

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/547483.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Pechkin:html - pdf 利器

Pechkin 是GitHub上的一个开源项目&#xff0c;可方便将html转化成pdf文档&#xff0c;使用也很方便&#xff0c;下面是winform项目中的示例代码&#xff1a; using System; using System.Diagnostics; using System.Drawing.Printing; using System.IO; using System.Windows.…

packer build 报错 无任何输出 一直报“skipping line: 1 skipping line: 2 skipping line: 3.....”

最近使用packer build 报错 无任何输出 一直报“skipping line: 1 skipping line: 2 skipping line: 3.....” &#xff0c; 解决方法如下&#xff1a; # Install wget and unzip before executing the below steps wget https://releases.hashicorp.com/packer/1.0.0/packer_…

使用ZeroClipboard解决跨浏览器复制到剪贴板的问题

Zero Clipboard的实现原理Zero Clipboard 利用透明的Flash让其漂浮在复制按钮之上&#xff0c;这样其实点击的不是按钮而是 Flash &#xff0c;这样将需要的内容传入Flash&#xff0c;再通过Flash的复制功能把传入的内容复制到剪贴板。 Zero Clipboard的安装方法首先需要下载 …

android inflate 三个参数的含义,LayoutInflater.inflate 3个参数的含义

LayoutInflater.inflate 天天都在用但对它 3 个参数的含义没有很好的理解之前 root 一直传 null , 现在才知道传 null 在多数情况下都是不对的public View inflate(LayoutRes int resource, Nullable ViewGroup root, boolean attachToRoot)第一个参数是布局ID 没什么说的第二个…

详解UML中的聚合,关联,泛化等关系

1. Overview UML设计类中&#xff0c;类的关系分为Generalization(泛化)&#xff0c;Dependency(依赖关系)、Association(关联关系)、Aggregation(聚合关系)、Composition(组合关系)五种! 2. Generalization(泛化) Generalization(泛化)表现为继承或实现关系(is a)。具体形式为…

CentOS 8 安装 Docker  报错  requires containerd.io >= 1.4.1, but none of the providers can be installed

CentOS 8.1安装 Docker 官方参考地址&#xff1a;https://docs.docker.com/install/linux/docker-ce/centos/ 里面包含包下载地址&#xff1a;https://download.docker.com/linux/centos/8/x86_64/stable/Packages/containerd.io-1.4.3-3.1.el8.x86_64.rpm 一。确认CentOS 版…

PHP获取图片宽度高度、大小尺寸、图片类型、用于布局的img属性

//php自带函数 getimagesize()$img_info getimagesize(tomener.jpg); echo <pre>; print_r($img_info); 输出&#xff1a; Array ( [0] > 170 [1] > 254 [2] > 2 [3] > width"170" height"254" [bits] > 8 [channels] > 3 […

CentOS 8安装并配置NFS服务

先决条件 我们假设您有一台运行CentOS 8的服务器&#xff0c;我们将在该服务器上设置NFS服务器和其他充当NFS客户端的计算机。服务器和客户端应该能够通过专用网络相互通信。如果您的托管服务提供商不提供私有IP地址&#xff0c;则可以使用公共IP地址并配置服务器防火墙&#…

android.support.v7 fragme,打造最强RecyclerView侧滑菜单,长按拖拽Item,滑动删除Item

前几天写了一片关于RecyclerView滑动删除Item&#xff0c;RecyclerView长按拖拽Item的博客&#xff0c;本来很简单一个使用&#xff0c;阅读量还挺高的&#xff0c;原博客传送门。今天介绍一个RecyclerView Item侧滑菜单&#xff0c;RecyclerView滑动删除Item&#xff0c;Recyc…

有关PHP、HTML单引号、双引号转义以及转成HTML实体的那些事!

一、单引号和双引号转义在PHP的数据存储过程中用得比较多&#xff0c;即往数据库里面存储数据时候需要注意转义单、双引号&#xff1b; 先说几个PHP函数&#xff1a; 1、addslashes — 使用反斜线引用&#xff08;转义&#xff09;字符串&#xff1b; 返回字符串&#xff0c;…

设为首页 和 收藏本站js代码 兼容IE,chrome,ff

设为首页 和 收藏本站js代码 兼容IE,chrome,ff//设为首页function SetHome(obj,url){try{obj.style.behaviorurl(#default#homepage);obj.setHomePage(url);}catch(e){if(window.netscape){try{netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect&q…

android listview 数据数组制作,android – 从对象的数组列表中填充listview

在你的活动AdapterPerson adbPerson;ArrayList myListItems new ArrayList();//then populate myListItemsadbPerson new AdapterPerson (youractivity.this, 0, myListItems);listview.setAdapter(adbPerson);适配器public class AdapterPerson extends ArrayAdapter {privat…

centos 8 安装使用配置

服务端安装nfs 1、使用yum安装nfs yum install nfs-utils nfs-utils-lib -y 如果出现上述错误请安装lvm2 yum install -y lvm2 2、编辑文件exports vim /etc/exports 加入代码&#xff0c;如&#xff1a; /home *(insecure,rw,sync,no_root_squash) #参数详解 ro #只读共享…

linux内核笔记-内核同步

linux内核就相当于不断对请求进行响应的服务器&#xff0c;这些请求可能来自CPU&#xff0c;可能来自发出中断的外部设备。我们将内核看作两种请求的侍者。 &#xff08;1&#xff09;老板提出请求&#xff0c;侍者如果空闲&#xff0c;为老板服务。&#xff08;系统调用或异常…

ECshop 快捷登录插件 支持QQ 支付宝 微博

亲自测试可以使用&#xff0c;分享给大家。(承接各种EcShop改版&#xff0c;二次开发等相关项目 QQ:377898650) 安装的时候按照里面说明。安装即可。 代码下载&#xff1a;http://pan.baidu.com/s/1c0kUYIk -------------------------------- 代码修改过程-------------首先a…

Net连接mysql的公共Helper类MySqlHelper.cs带MySql.Data.dll下载

MySqlHelper.cs代码如下&#xff1a; using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Text;using System.Data;using System.Collections;using MySql.Data.MySqlClient;using MySql.Data.Types;using System.Configuration;…

有史以来最详细 安装部署Kubernetes Dashboard (补充解决官方出现的一些RBAC CERT等问题)

安装部署Kubernetes Dashboard (补充解决官方出现的一些RBAC CERT等问题) 官方文档&#xff1a;https://github.com/kubernetes/dashboard 参考文章&#xff1a;https://kuboard.cn/install/install-k8s-dashboard.html# 前言 Kubernetes Dashboard 是 Kubernetes 的官方 W…

技术者的好奇心和惯性

这回老孙讲讲好奇心。本杰明富兰克林&#xff0c;十八世纪美国最伟大的科学家和发明家&#xff0c;著名的政治家、外交家、哲学家、文学家和航海家以及美国独立战争的伟大领袖。有人称其为“资本主义精神最完美的代表”。富兰克林这个人或许衬不上这等称誉&#xff0c;但绝对是…

2s相机 android6,Android Camera2 使用总结

最近在做自定义相机相关的项目&#xff0c;网上查了资料都是有关android.hardware.Camera的资料&#xff0c;开始使用的才发现这个类已经废弃了。Android 5.0(21)之后android.hardware.Camera就被废弃了&#xff0c;取而代之的是全新的android.hardware.Camera2 。Android 5.0对…

简单的小工具wordlight——让VS变量高亮起来

前段时间一直在使用matlab&#xff0c;今天需要使用vs2008&#xff0c;而用惯了matlab&#xff0c;习惯了其中一项选中变量高亮的设置&#xff0c;突然回来使用VS&#xff0c;感到各种不适应&#xff0c;顿时想到了一个词&#xff1a;矫情 呵呵&#xff0c;于是在网上找各种插…