I'm trying to move an image from right to left doing a "V" (up-down-up). Here's an image describing what I'm after:
I tried using ObjectAnimator
and AnimatorSet
but I'm not getting what I was hopping to get. And it's hard to understand why I'm getting something else.
Here's my current code:
/**
* translateLeft = -160dp
* translateDown = 25dp
* translateUp = -25dp
*/
private void vShapedAnimation () {
AnimatorSet upDownSet = new AnimatorSet();
AnimatorSet downUpSet = new AnimatorSet();
AnimatorSet finalSet = new AnimatorSet();
ObjectAnimator rightToLeft = ObjectAnimator.ofFloat(this.imageView, View.TRANSLATION_X, this.getResources().getDimensionPixelOffset(R.dimen.translateLeft) / 2);
ObjectAnimator upDown = ObjectAnimator.ofFloat(this.imageView, View.TRANSLATION_Y, this.getResources().getDimensionPixelOffset(R.dimen.translateDown));
ObjectAnimator downUp = ObjectAnimator.ofFloat(this.imageView, View.TRANSLATION_Y, this.getResources().getDimensionPixelOffset(R.dimen.translateUp));
upDownSet.playTogether(
rightToLeft,
upDown
);
downUpSet.playTogether(
rightToLeft,
downUp
);
finalSet.playSequentially(
upDownSet,
downUpSet
);
finalSet.setDuration(300);
finalSet.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
animation.removeListener(this);
animation.setDuration(0);
animation.setInterpolator(new ReverseInterpolator());
animation.start();
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
finalSet.start();
}
The ReverseInterpolator
in the AnimatorListener
comes from here:
I'm planning to rotate the image a bit at the same time. And if the "V" could be curved inward a tiny bit, that would be perfect. But if, at first, someone could help me do the basic animation, it would be deeply appreciated.
ObjectAnimator
has its weird moments, but I finally got the hang of it (at least enough to solve my own problem).
The catch is that, in a sequence of animations, it is better to always indicate the starting position as well as the ending position. In the question I wrote, the three ObjectAnimators
were only given the ending position. That makes the animation start in weird places.
Using a pseudo-code example, if you want to go from A to C going through B, you need to write it down as so:
ObjectAnimator AtoB_X = ObjectAnimator.ofFloat(this.imageView, View.TRANSLATION_X, A.x, B.x - A.x);
ObjectAnimator BtoC_X = ObjectAnimator.ofFloat(this.imageView, View.TRANSLATION_X, B.x - A.x, C.x - A.x);
ObjectAnimator AtoB_Y = ObjectAnimator.ofFloat(this.imageView, View.TRANSLATION_Y, A.y, B.y - A.y);
ObjectAnimator BtoC_Y = ObjectAnimator.ofFloat(this.imageView, View.TRANSLATION_Y, B.y - A.y, C.y - A.y);
IMPORTANT: always use dp
measurements. Never use px
measurements. That is why, in my code, I use this.getResources().getDimensionPixelOffset()
. It converts the dp
value to a px
value appropriate to each screen resolution.
Now, for my working code:
private void vShapedAnimation() {
AnimatorSet upDownSet = new AnimatorSet();
AnimatorSet downUpSet = new AnimatorSet();
AnimatorSet finalSet = new AnimatorSet();
ObjectAnimator rightToHalf = ObjectAnimator.ofFloat(this.imageView, View.TRANSLATION_X, 0, this.getResources().getDimensionPixelOffset(R.dimen.translateLeft) / 2);
ObjectAnimator halfToLeft = ObjectAnimator.ofFloat(this.imageView, View.TRANSLATION_X, this.getResources().getDimensionPixelOffset(R.dimen.translateLeft) / 2, this.getResources().getDimensionPixelOffset(R.dimen.translateLeft));
ObjectAnimator upDown = ObjectAnimator.ofFloat(this.imageView, View.TRANSLATION_Y, 0, this.getResources().getDimensionPixelOffset(R.dimen.translateDown));
ObjectAnimator downUp = ObjectAnimator.ofFloat(this.imageView, View.TRANSLATION_Y, this.getResources().getDimensionPixelOffset(R.dimen.translateDown), 0);
upDownSet.playTogether(
rightToHalf,
upDown
);
downUpSet.playTogether(
halfToLeft,
downUp
);
finalSet.playSequentially(
upDownSet,
downUpSet
);
finalSet.setInterpolator(new LinearInterpolator());
finalSet.setDuration(300);
finalSet.start();
}