目标效果

触发后,金币左右抖动多次,向上移动并消失,文字向下移动显示
实现方式似乎很简单,依次实现上述三个动画即可
而本文主要展示我在第一个动画的探索过程
版本1
我们需要保持动画结束时的状态,故采用属性动画。
ObjectAnimator.ofFloat(iv_coin, "translationX", -100f, 100f).apply {
duration = 1000
repeatCount = 2
repeatMode = ValueAnimator.REVERSE
}.start()

存在问题,动画播放开始时,金币直接跳到左边,而非缓慢移动到左边,导致动画开始时和结束时很突兀。
版本2
针对发现的原因,我们把中点到左边的过程也纳入动画中,
改变如下
原本: left -> right
现在: mid -> left -> mid -> right -> mid
同时,重复模式也要改成RESTART
, 原因,动画重复时,当前定义的路径是不能翻转的。
ObjectAnimator.ofFloat(iv_coin, "translationX", 0f, -100f, 0f, 100f, 0f).apply {
duration = 1000
repeatCount = 2
repeatMode = ValueAnimator.RESTART
}.start()

存在问题,重复播放到中点时,金币摆动的速度会变得很慢,后才逐渐加快
版本3
一直误以为插值器是匀速线性,即LinearInterpolator
,导致的这个错误认知的原因应该来源于这个方法。
当设的值为空时,便设为LinearInterpolator
@Override
public void setInterpolator(TimeInterpolator value) {
if (value != null) {
mInterpolator = value;
} else {
mInterpolator = new LinearInterpolator();
}
}
而实际上默认的插值器是非线性的,即AccelerateDecelerateInterpolator
,先加速后减速。仔细想想使用这个插值器更加合理,更加接近自然效果。
生活中,当我们用力推动一个小球一段时间,加速到减速的过程更加符合实际。
而这里,我们尝试将插值器改为线性的。
ObjectAnimator.ofFloat(iv_coin, "translationX", 0f, -100f, 0f, 100f, 0f).apply {
duration = 1000
repeatCount = 2
interpolator=LinearInterpolator()
repeatMode = ValueAnimator.RESTART
}.start()

存在问题,摆动的整个过程很僵硬,不符合自然效果。
版本4
为了让金币摆动自然,我的方案是将金币摆动的过程分为三个动画实现,每个动画使用默认的插值器。
动画1:mid -> left
动画2:left -> right
动画3:right -> mid
注意duration时间的分配
AnimatorSet().apply {
val xDuration = 1000L
val xOffset = 100f
playSequentially(
ObjectAnimator.ofFloat(iv_coin, "translationX", -xOffset)
.setDuration((xDuration / 2)),
ObjectAnimator.ofFloat(iv_coin, "translationX", -xOffset, xOffset).apply {
duration = xDuration
repeatMode = ValueAnimator.REVERSE
repeatCount = 2
},
ObjectAnimator.ofFloat(iv_coin, "translationX", 0f).setDuration((xDuration / 2))
)
}.start

效果已经符合我的需求,不知道有没有更好的实现方式?