Android怎么使用cos和sin绘制复合曲线动画
这篇文章将为大家详细讲解有关Android怎么使用cos和sin绘制复合曲线动画,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。
在开发新需求的时候,设计给了一份类似这样的动画:
看着不难,即使一遍看不懂,嘿嘿,不还有设计稿。
作为一个平时很少写动画的 Android 开发仔,看到一段段的缓入缓出曲线的设计稿时,我的心情是这样的:
虽然,Android 动画默认的插值器 AccelerateDecelerateInterpolator 有这样缓入缓出的效果:
我总不能一整个动画给它拆成4段动画来写,还别说,我第一次写的代码还真的是这么干的。
第一次分析
本着能少写一行绝不多写一字的原则,询问了大佬同事的意见,大佬大手一挥:PathInterpolator(后证实有问题)。
简单看了一下使用方式,需要使用 Path,再看了一眼,好家伙,有可能会用到贝塞尔曲线,放弃~
为了能够快速的解决问题,就使用了上面谈到的方案:
privatefunanimateTagView(tagView:TextView){ //[0,200]区间的动画 valvalueAnimatorOne=ValueAnimator.ofInt(0,200) valueAnimatorOne.addUpdateListener{ valper=it.animatedValueasInt/200f tagView.rotation=4*per tagView.scaleX=(1-0.1*per).toFloat() tagView.scaleY=(1-0.1*per).toFloat() } valueAnimatorOne.duration=200 //[200,560]区间的动画 valvalueAnimatorTwo=ValueAnimator.ofInt(200,560) valueAnimatorTwo.addUpdateListener{ valper=(it.animatedValueasInt-200)/360f tagView.rotation=3-11*per tagView.scaleX=(0.9+0.1*per).toFloat() tagView.scaleY=(0.9+0.1*per).toFloat() } valueAnimatorTwo.duration=360 //[560,840]区间的动画 valvalueAnimatorThree=ValueAnimator.ofInt(560,840) valueAnimatorThree.addUpdateListener{ valper=(it.animatedValueasInt-560)/280f tagView.rotation=-8+12*per tagView.scaleX=(1-0.2*per).toFloat() tagView.scaleY=(1-0.2*per).toFloat() } valueAnimatorThree.duration=280 //[840,1000]的动画 valvalueAnimatorFour=ValueAnimator.ofInt(840,1000) valueAnimatorFour.addUpdateListener{ valper=(it.animatedValueasInt-840)/160f tagView.rotation=4-4*per tagView.scaleX=(0.8+0.2*per).toFloat() tagView.scaleY=(0.8+0.2*per).toFloat() } valueAnimatorFour.duration=160 //使用AnimatorSet串行执行动画 valanimationSet=AnimatorSet() animationSet.playSequentially(valueAnimatorOne,valueAnimatorTwo,valueAnimatorThree,valueAnimatorFour) tagView.post{ tagView.pivotX=0f tagView.pivotY=ad_tag_two.measuredHeight.toFloat() animationSet.start() } }
整个动画被我拆成了[0,200]、[200,560]、[560,840]和[840,1000]四段属性动画,因为产品说只需要播放一次,所以使用 AnimatorSet 将动画组装起来,就可以解决问题。
第二次分析
第一次得到的方案虽然能够解决问题,如果遇到循环播放,AnimatorSet 就不行了,有没有其他方案呢?
趁着周末的时间,学了一下 PathInterpolator,发现这个玩意也解决不了问题,或者说不好解决问题,虽然可以用三阶贝塞尔曲线分段画出上述曲线,但 PathInterpolator 要求起点和终点分别在 (0,0) 和 (1,1)。
既然插值器不行,可以试试估值器,但一个估值器也解决不了旋转和缩放两种动画,看来得靠 AnimatorUpdateListener 去解决问题。
回头想一下,插值器是将均匀的时间片段转化成加速或者减速的行为,我们也可以将均匀的时间片段转化成对应的曲线,只要做好两点:
使用线性的插值器 LinearInterpolator。将上面的曲线拆分,通过不同的 sin 或者 cos 方法表达。以旋转动画为例,拆成的 sin 函数:
另外一段动画的函数可以参考代码:
overridefunonCreate(savedInstanceState:Bundle?){ super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) valtvContent=findViewById<TextView>(R.id.tv_content) valvalueAnimatorOne=ValueAnimator.ofFloat(0.0f,1.5f) valueAnimatorOne.addUpdateListener{ //通过对应的sin和cos设置rotation和scale valper=it.animatedValueasFloat varrotation:Float=0f varscale:Float=0f if(per>=0&&per<0.2f){ rotation=sin((per/0.2f)*Math.PI.toFloat()-Math.PI.toFloat()/2)*1.5f+1.5f scale=cos(per/0.2f*Math.PI.toFloat())*0.05f+0.95f } if(per>=0.2f&&per<0.56f){ rotation=sin(Math.PI.toFloat()/2+Math.PI.toFloat()*(per-0.2f)/0.36f)*5.5f-2.5f scale=cos((per-0.2f)/0.36f*Math.PI.toFloat()+Math.PI.toFloat())*0.05f+0.95f } if(per>=0.56f&&per<0.84f){ rotation=sin(Math.PI.toFloat()*(per-0.56f)/0.28f-Math.PI.toFloat()/2)*6f-2f scale=cos((per-0.56f)/0.28f*Math.PI.toFloat())*0.1f+0.9f } if(perin0.84f..1f){ rotation=sin(Math.PI.toFloat()/2+Math.PI.toFloat()*(per-0.84f)/0.16f)*2f+2f scale=cos((per-0.84f)/0.16f*Math.PI.toFloat()+Math.PI.toFloat())*0.1f+0.9f } //设置停止时间 if(per>1f&&per<=1.5f){ rotation=0f scale=1.0f } tvContent.rotation=rotation tvContent.scaleX=scale tvContent.scaleY=scale } //设置线性插值器 valueAnimatorOne.interpolator=LinearInterpolator() //动画时间 valueAnimatorOne.duration=1500 //无线循环 valueAnimatorOne.repeatCount=-1 tvContent.post{ //设置中心点 tvContent.pivotX=0f tvContent.pivotY=tvContent.measuredHeight.toFloat() valueAnimatorOne.start() } }
整个代码还是比较简单的,旋转动画曲线由 sin 得出,缩放由 cos 得出,最后改一下中心点。
关于“Android怎么使用cos和sin绘制复合曲线动画”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。
推荐阅读
-
怎么使用Android基准配置文件Baseline Profile方案提升启动速度
-
HTML5如何实现禁止android视频另存为
-
学java好还是学php好?
-
Android如何实现多点触控功能
-
android怎么实现多点触摸应用
-
Android怎么实现手势划定区域裁剪图片
-
android怎么实现简单的矩形裁剪框
-
Android单选多选按钮怎么使用
-
Android中如何利用oncreate获取控件高度或宽度
Android中如何利用oncreate获取控件高度或宽度本篇内容...
-
Android中怎么使用onSaveInstanceState()方法
Android中怎么使用onSaveInstanceState()方法...