您的位置:首页 > 其它

自定义View之小球自由落体弹跳加载控件

2017-09-14 08:00 232 查看


今日科技快讯
继小米MIX 2和iPhone X之后,三星Note 8国行发布会也于昨晚18点在北京51D·PARK 时尚设计广场举行。但是相比于小米和苹果,三星在中国市场上可谓步履维艰,所以三星对Note 8寄予了厚望。国行版Note 8对于S8做了一定程度的提升。这款手机使用骁龙835处理器,内置6GB的RAM,有64,128,256GB三种规格的ROM可选,支持IP68防水设计,电池容量3300毫安时,保留了USB-C和3.5mm耳机接口。Note 8的屏幕采用了全视曲面屏的设计,不过屏幕尺寸比S8系列要更大,达到了6.3英寸,屏幕比例则依然维持在18.5:9以及2K级别的分辨率。同时三星Note 8也成为了全球首款解决了双摄像头同时支持OIS光学防抖的手机产品。
作者简介
本篇来自 勇朝陈 的投稿,详细地讲解了一个关于小球自由落体弹跳加载的自定义控件,希望大家喜欢!
[b][b][b][b]勇朝陈[/b][/b][/b][/b] 的博客地址:
http://blog.csdn.net/ccy0122
效果预览
因 GIF 图压缩的原因动画看起来有些不流畅。



应用为加载框的效果: 



使用方法
XML:



可用的属性
属性名称作用
bounce_count小球弹跳次数
ball_color小球颜色
ball_count小球数量
ball_radius小球半径
ball_delay小球出现时间间隔(当小球数大于1时)
anim_duration小球一次动画时长
physic_mode开启物理效果(下落加速上升减速)
random_color开启小球颜色随机
random_radius开启小球大小随机(在基础大小上下浮动)
random_path开启小球路径随机(在基础路径坐标上下浮动)
也可以在代码中进行配置:



最后开启动画:



实现思路
源码地址:
https://github.com/CCY0122/bounceballview
概况
该自定义控件主要是使用了 Path 和属性动画来完成的,比如小球的弹跳路径,是用 Path 和二次贝塞尔曲线来完成的,再比如这个小球“下落加速、上弹减速”的仿物理效果是利用了 Path 插值器(PathInterpolator)和三次贝塞尔曲线完成的,另外诸如颜色随机、小球大小随机这些都是通过监听属性动画来实现的。接下来会讲解下这些主要的实现思路 。
对于自定义 View 的其他基本流程,如属性的获取与设置、onMeasure 的重写等本文不会多讲,想了解完整流程的话可以查看源码。
小球路径的实现
通过效果图可以看到,只要确定了控件大小和小球弹跳次数(bounce_count),那么就能确定小球总体的弹跳路径。因此第一个核心点就是实现小球路径的 Path。假设bounce_count 值被设置为3,即弹跳3次,那么路径 Path 的效果图应该如下图所示: 



要绘制出上述这样的路径,可以利用多个二次贝塞尔曲线拼接的方式实现。关于贝塞尔曲线,若想课后系统的学习,我很推荐徐医生的这篇文章:
http://blog.csdn.net/eclipsexys/article/details/51956908
对于二次贝塞尔曲线,这里引用一张经典图:



一张图真是胜过千言万语啊~
在 path 中二次贝塞尔对应的方法是 path.quadTo (float x1, float y1, float x2, float y2),其中,x1/y1 对应上图 P1 点,称做控制点,x2/y2 对应 P2 点,就叫他终点把,P0点么就是当前 path 所在的起点。 
由此可见,上图小球弹跳路径就是通过拼接4个二次贝塞尔曲线完成的,对于代码中对起点、终点、控制点的确定,为了方便理解,在看代码前,先附上一张图: 



一张图真是胜过千言万语啊~
path 的实现代码如下:



配合图片看代码,其中 PathMeasure 是一个用于测量 path 各种数据的帮助类,通过它我们可以获取一段 path 的长度、path 上某一点的坐标等等,非常有用。关于它的详细使用,可参考:
http://blog.csdn.net/eclipsexys/article/details/51992473
在代码中我们还记录了一个变量 skipLength 即对于上图中的AB段,因为我们的小球是直接从最高点开始下落的,所以AB段我们是要省略掉的。另外关键的一点是还记录了segmentLength[] 数组,它的作用是用来后面创建插值器时用到的。对于上图来讲, segmentLength 中分别存储着 AC、AD、AE、AF 四段路径长度。 
有了弹跳路径,在 onDraw 中我们就可以利用 PathMeasure 来取出路径上某一个点的坐标,作为小球的绘制坐标了,而具体要取哪个点呢?我们可以通过属性动画来控制一个数值在一定时间内从0.0开始变化到1.0结束,将这个值作为比例值乘上路径总长度,就能得到当前时间要取的坐标点了,代码如下:



在 onDraw 中,translateFraction[i] 记录着第i个小球当前的属性动画值。通过pathMeasure.getPosTan(pathMeasure.getLength()*translateFraction[i],pos,tan); 方法获取了当前比例值下路径上对应点的坐标值(存放在 pos[2] 数组里)和正切值(存放在 tan[2] 数组里),获取到了这个坐标点后,再经过一步路径随机的判断处理后,我们就可以通过 canvas.drawCircle 来画出小球了。 
那么接下来我们的重点就是属性动画了。
小球动画的实现
通过上述分析可知,小球的动画其实是对一个比例值做动画,让这个值在一定时间内从0.0开始变化到1.0,并且无限循环。同时通过监听动画,在动画过程中可以对小球的透明度、颜色、路径、大小做相应的改变,当然还有最重要的就是在动画监听过程中不断的调用 invalidate() 来重绘小球的坐标位置。创建动画的代码如下:



有多少个小球,就创建了多少个动画,并存储在 translateAnim[] 数组里。如果开启了仿物理效果,就会给动画设置一个插值器setInterpolator(physicInterpolator) ,后面会讲解这个插值器的实现。另外监听了动画开始和动画循环时的监听回调,在里面调用了makeRandom(index)方法,即对一些数据做随机处理,代码如下:



之后是监听了动画过程中的实时回调,在该回调中获取的当前动画进度比例 animation.getAnimatedFraction() 并赋值给了 translateFraction[index] ,然后还对小球做了透明度处理(效果图中可见:小球出现时由透明渐变到不透明,快结束时再渐变到透明)。最后就是调用了 invalidate() 去重绘小球。到这里,我们的控件已经成型了。
仿物理效果插值器的实现
我们的目标是要根据小球的弹跳次数来实现一个多次“减速-加速”的插值器,怎么实现呢?难道要继承基础插值器 BaseInterpolator 然后自己设计算法来写一个插值器吗?也太难了吧。 
我们这里要介绍一个神奇的插值器,叫 PathInterpolator。它可以将一个 path 路径映射成对应的插值器。 
举个例子,系统内置的加速插值器和减速插值器对应的图形如下: 





那么我们想要一个先减速后加速的插值器就应该大致长这样:



然后将多个这样的路径拼接,就能实现多次先减速后加速的插值器了 
但是这个路径怎么实现呢?从上图其实就可以看出来,当然是使用三次贝塞尔曲线啦,看到图中有红蓝两个点没有,他们就是两个控制点。若有不理解了,打开这个网站玩一玩就明白了:
http://cubic-bezier.com/#.2,.55,.8,.45
path 中三次贝塞尔曲线对应的方法是 path.cubicTo (float x1, float y1, float x2, float y2, float x3, float y3) 其中 x1/y1 为第一个控制点坐标, x2/y2 为第二个控制点坐标, x3/y3 为终点坐标。
最后还有一个问题就是要确定每一次“减速-加速”路径的起点和终点,这主要是通过之前在 initPath 里记录好的 segmentLength 来确定的。 
完整代码如下:





好了,到这里本控件主要的实现点都讲完了。想了解完整流程的可阅阅读源码:
https://github.com/CCY0122/bounceballview
谢谢阅读,欢迎 star。
更多
每天学习累了,看些搞笑的段子放松一下吧。关注最具娱乐精神的公众号,每天都有好心情。



如果你有好的技术文章想和大家分享,欢迎向我的公众号投稿,投稿具体细节请在公众号主页点击“投稿”菜单查看。

欢迎长按下图 -> 识别图中二维码或者扫一扫关注我的公众号:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: