Android怎么使用cos和sin绘制复合曲线动画

这篇文章将为大家详细讲解有关Android怎么使用cos和sin绘制复合曲线动画,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

在开发新需求的时候,设计给了一份类似这样的动画:

Android怎么使用cos和sin绘制复合曲线动画

看着不难,即使一遍看不懂,嘿嘿,不还有设计稿。

Android怎么使用cos和sin绘制复合曲线动画

作为一个平时很少写动画的 Android 开发仔,看到一段段的缓入缓出曲线的设计稿时,我的心情是这样的:

虽然,Android 动画默认的插值器 AccelerateDecelerateInterpolator 有这样缓入缓出的效果:

Android怎么使用cos和sin绘制复合曲线动画

我总不能一整个动画给它拆成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 函数:

Android怎么使用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绘制复合曲线动画”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

发布于 2021-03-17 20:53:38
收藏
分享
海报
0 条评论
167
上一篇:JavaScript深拷贝的注意事项 下一篇:R语言绘图布局的案例分析
目录

    0 条评论

    本站已关闭游客评论,请登录或者注册后再评论吧~

    忘记密码?

    图形验证码