Android Property Animation — The ValueAnimator

ValueAnimator provides a timing engine for running animation which calculates the animated values and set them on the target objects. By ValueAnimator you can animate a view width, height, update its x and y coordinates or even can change its background.

It has an interface ValueAnimator.AnimatorUpdateListener which is used to receive callbacks on every animation frame.

ValueAnimator widthAnimator = ValueAnimator.ofInt(10, 100);
widthAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int animatedValue = (int) animation.getAnimatedValue();
someView.getLayoutParams().width = animatedValue;
someView.requestLayout();
}
});

In above example, I’m updating the width of a view from 10 to 100. In onAnimationUpdate() method the animated value is used to update the width of that view. On calling requestLayout() the framework will redraw the view according to updated width value (this method is needed to be called on every change of value otherwise the view will not be redrawn according to updated value and effect would not be seen).

Besides this simple example, let’s have a look at a little complex one. In this example, I’m going to change x and y coordinates and size of the button on click of a floating action button. And result is shown below —

Using value animator

Animating a single value with ValueAnimator is straightforward. ValueAnimator provides the static method like ofInt and ofFloat to animate between integer and floating point values.

AnimatorSet buttonAnimator = new AnimatorSet();

/**
* ValueAnimator to update x position of a button
*/
ValueAnimator buttonAnimatorX = ValueAnimator.ofFloat(startPositionX, pentagonVertices[position].x);
buttonAnimatorX.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
button.setX((float) animation.getAnimatedValue() - button.getLayoutParams().width / 2);
button.requestLayout();
}
});
buttonAnimatorX.setDuration(ANIMATION_DURATION);

/**
* ValueAnimator to update y position of a button
*/
ValueAnimator buttonAnimatorY = ValueAnimator.ofFloat(startPositionY, pentagonVertices[position].y);
buttonAnimatorY.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
button.setY((float) animation.getAnimatedValue());
button.requestLayout();
}
});
buttonAnimatorY.setDuration(ANIMATION_DURATION);

In the above code startPositionX & startPositionY are the center coordinates of floating action button and pentagonVertices[position].x, pentagonVertices[position].y are destination coordinates which are calculated by —

/**
* Calculating the coordinates of vertices of pentagon
*/
for (int i = 0; i < NUM_OF_SIDES; i++) {
pentagonVertices[i] = new Point((int) (radius * Math.cos(rotation + i * 2 * Math.PI / NUM_OF_SIDES)) + centerX,
(int) (radius * Math.sin(rotation + i * 2 * Math.PI / NUM_OF_SIDES)) + centerY - 100);
}

So what actually happening is the valueAnimator is animating from startPositionX and startPositionY to the pentagonVertices[position].x and pentagonVertices[position].x. And in onAnimationUpdate() we are setting these animated value to x and y of a button.

Same thing is happening with the size of button —

ValueAnimator buttonSizeAnimator = ValueAnimator.ofInt(5, width);
buttonSizeAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
button.getLayoutParams().width = (int) animation.getAnimatedValue();
button.getLayoutParams().height = (int) animation.getAnimatedValue();
button.requestLayout();
}
});
buttonSizeAnimator.setDuration(ANIMATION_DURATION);
buttonAnimator.start();

It is obvious that we need to update both the x and y coordinates. The naive approach is to create two animations and play them simultaneously, but it is not efficient. We can use PropertyValuesHolder to combine multiple values which I’ll demonstrate in my next post.

By default, ValueAnimator uses non-linear time interpolation, via the AccelerateDeccelerateInterpolator class, which accelerates into and decelerates out of an animation. This behavior can be changed by calling setInterpolator(Time Interpolator).

You can see the full source code here : https://github.com/developer-shivam/PentagonFloatingActionButton

Thanks for reading! Be sure to click ❤ below to recommend this article if you found it helpful. It means a lot to me.

For more about programming, follow me and Mindorks , so you’ll get notified when I write new posts.

Check out all the Mindorks best articles here.

Also, Let’s become friends on Linkedin, Github and Facebook.