Introduction to Physics-based animations in Android
Physics-based animation relies on the laws of physics to manifest a high degree of realism in animation.
What is Physics-based animation?
- It’s an animation that is driven by force.
- Based on the force, acceleration or deceleration can be calculated, which can then be used to calculate and update the velocities and values for the animation at each frame.
- And finally, the animation comes to rest when the force reaches equilibrium.
How is it different?
- Natural: Animations look more natural and mimic real-time movements.
- Reactive: When the target value changes, animations keep momentum(velocity) and end with a smoother motion.
- Less visual disruption: Animations appear smoother and more responsive, and you see less disruption in animation.
Consider a scenario where the target value needs to change during the animation.
Animations that are built by using Animator are fairly static and have a fixed duration. To accommodate the change in the target value, you need to cancel the animation at the time of target value change, reconfigure the animation with current value as the new start value, and add the new target value. Visually, this process creates an abrupt stop in the animation, and a disjointed movement afterward.
Animations that are built by using the physics-based animation APIs are driven by force. The change in the target value results in a change in force. The new force applies on the existing velocity, which makes a continuous transition to the new target. This process results in a more natural-looking animation.
Adding Physics-based animation support library
In order to get started with the physics-based animations, add the physics-based support library to your build.gradle file.
compile "com.android.support:support-dynamic-animation:25.4.0"
The library provides two Animation classes: SpringAnimation and FlingAnimation.
Spring Animation
In real life when an object is attached to a spring, and when you pull that object, the string stretches. And when you release the object, it returns to its initial position with a bouncy spring effect.
To simulate that in our app, suppose your view has been animated to some different position and then you want your view to return back to its initial position with a bouncy spring force that makes it oscillate before coming to rest at equilibrium. SpringAnimation class can easily do that for you.
Now, let’s learn a bit about properties of a spring before you see how to achieve this.
Spring Force
SpringForce class allows you to control the properties of a spring by changing its damping ratio, stiffness, and its resting position. As soon as the animation begins, the spring force updates the animation value and the velocity on each frame. The animation continues until the spring force reaches an equilibrium.
Damping ratio: Spring damping ratio controls the bounciness of a spring, i.e. number of oscillations before coming to rest. You can change the bounciness of the spring by simply setting the damping ratio. A damping ratio of zero would oscillate infinitely. A very high damping ratio will stop animating very quickly.
Damping ratio can range from high bouncy to no bouncy constants.
DAMPING_RATIO_HIGH_BOUNCY = 0.2f; // more oscillations
DAMPING_RATIO_NO_BOUNCY = 1f; // very few oscillations
Stiffness: Stiffness controls the strength of the spring, i.e. how fast the oscillation is. You can change the stiffness of the spring, which will control how quickly the object snaps back to its resting position.
Stiffness constants can range from high stiffness to very low stiffness.
STIFFNESS_HIGH = 10_000f; // would quickly come back to its resting position
STIFFNESS_VERY_LOW = 50f; // would slowly come back, like a loose suspension
Resting position: That position where you want the spring force to reach the equilibrium.
To achieve the animation shown above, we create an instance of SpringAnimation class to animate the view’s translationX property :
SpringAnimation springX = new SpringAnimation(mViewToBeAnimated,
new FloatPropertyCompat<View>("translationX") {
@Override
public float getValue(View view) {
return view.getTranslationX();
}
@Override
public void setValue(View view, float value) {
view.setTranslationX(value);
}
});
SpringForce springForceX = new SpringForce(0f);
springForceX.setStiffness(SpringForce.STIFFNESS_MEDIUM);
springForceX.setDampingRatio(SpringForce.DAMPING_RATIO_HIGH_BOUNCY);
springX.setSpring(springForceX);
springX.start();
To the constructor of SpringAnimation, we provide the view that we want to animate and the property that we want to animate. The object we want to animate in this case is imageView and the property we want to animate is TRANSLATION_X since we want to bounce the view left and right. We create a springForce instance and set the value of the final resting position of the spring to zero so that the view will spring back to its starting point.
And finally start the spring animation, when you release the finger.
And voila, your view has got the magical spring force now!
Fling Animation
Now, after bouncing a view, let’s see how to fling a view which simulates like a real-world object being flung in space. When you fling an object in the real world, you give the object some initial velocity, and that’s usually the velocity of your gesture, and then it would continue to travel with some momentum before gradually coming to rest. It came to rest due to friction force it experienced which slowed down its velocity until it stopped.
For simulating this fling behavior and a graceful end to the animation, we would use FlingAnimation class available in the library.
For an example here, let’s see how to fling a view across x and y-axis depending upon the fling gesture direction.
In order to receive callbacks, when a fling gesture occurs, we need to set up a gesture listener. And once the fling gesture is detected, we receive the onFling callback with a downEvent, an upEvent and a velocity on both x- and y-axis. Velocity vX and vY will be in the unit pixels per second.
Setting StartVelocity
You need to set startVelocity for Fling Animation as by default the start velocity is set to zero pixels/sec. In that case, it would stop the animation in next frame. Therefore, you must define a start velocity to ensure the animation does not end right away.
Setting Minimum and Maximum value
Set the minimum and the maximum animation values when you want to animate the property value within a certain range. And once Fling Animation reaches either its minimum animation value or maximum animation value, it will end immediately.
Setting Friction
Also, set friction to control the rate of slowing down of animation, like how quickly/gradually you want the velocity to be decreased.
And now we are ready to create a Fling Animation.
private GestureDetector.OnGestureListener mGestureListener = new GestureDetector.SimpleOnGestureListener() {
...
@Overridepublic boolean onFling(MotionEvent downEvent, MotionEvent moveEvent, float velocityX, float velocityY) {
//Fling Right/Left
FlingAnimation flingX = new FlingAnimation(mViewTobeFlung, DynamicAnimation.TRANSLATION_X);
flingX.setStartVelocity(velocityX)
.setMinValue(MIN_TRANSLATION) // minimum translationX property
.setMaxValue(maxTranslationX) // maximum translationX property
.setFriction(FRICTION)
.start();
return true;
}
};
To FlingAnimation constructor, we provide the object we want to animate and the property that we want to animate. The object we want to animate in this case is imageView and the property we want to animate is TRANSLATION_X since we want to fling the imageView horizontally.
Finally, start the fling animation inside the onFling() method. And again, your view has started tuning and dancing with your finger!
Check out the project on GitHub for the complete working solution and also tinker with friction and velocity to check its effect on the animation.
Conclusion
With the new physics-based animation system, we don’t need to provide duration or start and end values for creating a physics-based animation. Google has empowered developers with an easy way to create cool animations that mimic the law of physics with just a few lines of code. Sounds cool! Try it yourself to super-power your animations.
Want to know more about it, listen to my talk I gave on "Animations + Physics = Cool App Transitions" at Droidcon Berlin, 2017. It has been uploaded on youtube, you can watch the video here.