您的位置:首页 > 其它

BouncingBallView 碰撞的小球

2017-09-26 00:00 316 查看


今日科技快讯
9月25日消息,今年年初就预测下半年行业会爆发全面屏浪潮的金立,今天发布了首款全面屏M7。但是,金立董事长刘立荣认为,18:9只是第一代全面屏,第二代或者未来全面屏将会被重新定义。随着苹果iPhone X全面屏的发布,全面屏在手机行业全面引爆。三星、小米、vivo也相继发布了全面屏产品。
作者简介
本篇来自 z1289042324 的投稿,分享了利用 Builder 模式,实现突发奇想的一个动画效果,希望大家喜欢!

[b][b][b][b][b][b][b]z1289042324 [/b][/b][/b][/b][/b][/b][/b] 的博客地址:
http://blog.csdn.net/z1289042324
前言
为了熟悉自定义 View 的操作流程,以及练习使用最近学到的 Builder 模式,再加上前几天脑袋里突发奇想的一个动画效果,所以就有了这篇文章。那就让我们来了解一下这好玩的技术吧!
正文
先上效果图吧



真机效果图
属性设置
在xml中设置





用到的变量如下



因为是小球的运动,那么自然就需要设置小球的个数,颜色,半径了,值的注意的是,这里 ballCount 的值设置为6,而效果途中有7个小球,至于为什么呢,是因为我将这几个小球分成了三部分。一个在摇摆中,一个在转动中,剩下的就是呆在他们各自的位置不动的了。正因为有一个在运动中以及一个在摇摆中,所以将整个圆均分的就少一个了,而  ballCount 的值正是将圆均分的个数。至于上面摇动中的小球角度等变量我将在下面通过几何图来介绍,而对于
BouncingViewConfig 这个类来说,不知道大家有没有注意到前言中提到的 Builder 模式,这是为了练习使用这个模式,所以我建了这个类,下面来看看这个类。



代码非常好懂,BouncingViewConfig 类保存了小球的一些属性,至于什么是 Builder 模式,以及 Builder 模式是干什么的,这里就不展开了。接下来就是几何分析了。
几何分析



先来分析一下这几个小球的几何分布,perAngle也就是小球将圆均分的角度,largeRadius为mWidth / 2 - ballRadius,看图应该很好懂,至于phaseAngle,它是两个小球在刚好相碰时的角度差,下面来计算一下。



这是两个小球碰撞的时候,两个小球相切,因为小球属性完全相同,所以两小球的交点与大圆圆心的连线是垂直于两小球圆心的连线的,简单的几何证明问题就不细说了,所以∠a = arcsin(ballRadius / largeRadius), 而角phaseAngle = 2 * a.好了,现在应该看看构造函数里的内容了。
构造函数



这个没什么好说的,就是将 xml 中设置的属性获取到,然后保存在一个BouncingViewConfig 引用中,看一下 init(config);



初始化 config 的内容以及初始化运动中小球的角度和摇摆小球的角度,下面讲讲这个角度的具体含义 



对于小球2来说,角 a1 就是它的角度,对于小球4来说角 a2 就是它的角度,不过此时 a2的值是负的,对于 y’ 轴来说,它的角度就是 0 度,总的来说就是以 y’ 轴为基准。说完角度,下面就说计算坐标的问题,注意此时的原点是整个大球的中心,所以得在 largeRadius * sina1 后再加上 mWidth / 2才是小球2的x坐标,y 坐标就是 largeRadius
* cosa1 + mWidth / 2。终于讲完了几何。
onMeasure



onMeasure 就是设置 mWidth 和 mHeight 以及计算各个角度了,计算方法前面已讲过。注意在计算 phaseAngle 时有个角度的转换,是因为 Math.asin 计算结果时弧度制,所以得转化成角度。
onDraw



在 onDraw 中就是根据各个小球得角度计算出所在得坐标,然后画出来。在其中有一个运动状态的判断,为什么呢?因为在整个动画中,是分成两个部分的。第一个部分运动小球重初始位置出发到它第一次与另一个小球相撞的过程,此时摇摆小球一直处于它的初始位置,是没有摇摆动画的,也就是 STATUS.FIRSTCYCLE,在动画中,摇摆小球和转动小球的初始位置就是上面的小球3的位置。第二个部分就是剩下的动画了,下面看一看画剩下的小球方法
drawRestBall(canvas)。



剩下的小球设定一个球为这几个中的第一个球,它的位置是在转动小球的逆时针第一个,在初始时,也就是小球2。然后这几个小球之间相差 perAngle 角度,一个循环就画出了剩下的小球。好了,接下来就是动画部分了
ValueAnimator





代码都已注释,很容易看懂。需要讲的时设置摇摆小球的摇摆动画时,有一个后退,然后前进的过程,也就是 0~-1~1 的过程,所以我选择了 sin 函数,sin0~sin(3/2 * π) 即wabbyBallAngle = wabbyBallStartAngle + (float) (Math.sin(fraction * 1.5 * PI) * phaseAngle);
在整个动画中,转动小球的结束,就是摇摆小球的开始,所以控制摇摆小球动画的开始我选择了在 onAnimationRepeat 中进行,不过这里面有一个坑,一个大坑,这个坑我目前还没有找到解决方法,在这里我希望各位前辈指点指点,那么这个坑是什么呢?不知各位有没有注意到效果图中下面的注释为真机图没有,那么我们来看看虚拟机中的图。



看,小球在碰撞时前方有个小球闪了一下,看看小球闪的位置,分析一波应该是转动小球下一次结束的位置,那么我们来给小球打个日志 



果然,有一个地方是异常的,在 onAnimationRepeat 执行后, runningBallAngle 突然变为了-107.24126,那么我们来看看runningBallAngle的赋值情况。在 onAnimationUpdate 中runningBallAngle = runningBallStartAngle - fraction * (perAngle
- phaseAngle) 也就是说它的位置应该是它的值初始值减去运动的偏移值。再看看小球闪动的时间,第一次闪动是在小球第一次碰撞的时候,也就是说应该实在 onAnimationRepeat 执行的时候,那就看看在 onAnimationRepeat 中的情况,runningBallStartAngle -= perAngle;每次重复运动小球开始运动的位置减去 perAngle,在效果图中就是60度。再看看日志中异常角度,-107.24126和-47.211426之间不就是相差60度吗?这就值得思考了,问题出在哪儿了呢,难道说是在fraction还没有到达1时就调用
onAnimationRepeat 吗?如果是这样的话runningBallAngle 在 onAnimationRepeat 中减去了60度,然后又在 onAnimationUpdate 中减去了 1*(perAngle - phaseAngle),这样就解释的通了。那么我们再打印一下 fraction的变化情况 。



果然,在 fracti 还没有到1时,就执行了 onAnimationRepeat,那为何在真机中没有出现这种问题呢?我们再用真机试一下。



看到这里,我的心是拔凉拔凉的,想来大家也知道怎么回事了,真机中并未有出现onAnimationRepeat 在 fraction 值变化结束之前调用的情况。拿了室友的魅族来测试,也是一样。查了一些资料也没找到什么解决方法,在这里向各位前辈请教请教。不过本文也应该结束了,哎,是不是忘了什么?说好的Builder呢?那么放上 MainActivity 中的内容吧。



可以看到,正是使用的Builder来保存 BouncingBallView 的配置信息,再加上效果图 。



到了这里,才是真的结束了。最后放上github地址:
https://github.com/imurluck/BouncingBallView
更多

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

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

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