Skip to content

Most visited

Recently visited

navigation

Spring Animation

Physics-based animations are driven by force. Spring force, is one such force that guides interactivity and motion. A spring force has the following properties: damping and stiffness. In a spring-based animation, the value and the velocity are calculated based on the spring force that are applied on each frame.

Lifecycle of a spring animation

In a spring-based animation, the SpringForce class lets you customize spring's stiffness, its damping ratio, and its final 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.

For example, if you drag an app icon around the screen and later release it by lifting your finger from the icon, the icon tugs back to its original place by an invisible but a familiar force.

Figure 1 demonstrates a similar spring effect. The plus sign (+) sign in the middle of the circle indicates the force applied through a touch gesture.

Spring release
Figure 1. Spring release effect

Building a spring animation

The general steps for building a spring animation for your application are as follows:

The following sections discuss the general steps of building a spring animation in detail.

Creating a spring animation

The SpringAnimation class lets you create a spring animation for a view. To build a spring animation, you need to create an instance of the SpringAnimation class and provide a view, a view’s property that you want to animate, and an optional final spring position where you want the animation to rest.

Note: At the time of creating a spring animation, the final position of the spring is optional. Though, it must be defined before starting the animation.

final View img = findViewById(R.id.imageView);
// Setting up a spring animation to animate the view’s translationY property with the final
// spring position at 0.
final SpringAnimation springAnim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y, 0);

The spring-based animation can animate views on the screen by changing the actual properties in the view objects. The following views are available in the system:

Registering listeners

The DynamicAnimation class provides two listeners: OnAnimationUpdateListener and OnAnimationEndListener. These listeners listen to the updates in animation such as when there is a change in the animation value and when the animation comes to an end.

OnAnimationUpdateListener

When you want to animate multiple views to create a chained animation, you can set up OnAnimationUpdateListener to receive a callback every time there is a change in the current view’s property. The callback notifies the other view to update its spring position based on the change incurred in the current view’s property. To register the listener, perform the following steps:

  1. Call the addUpdateListener() method and attach the listener to the animation.

    Note: You need to register the update listener before the animation begins. Though, update listener should be registered only if you need per-frame update on the animation value changes. An update listener prevents the animation from potentially running on a separate thread.

  2. Override the onAnimationUpdate() method to notify the other view about the change in the current view. The following sample code illustrates the overall use of OnAnimationUpdateListener.
// Creating two views to demonstrate the registration of the update listener.
final View view1 = findViewById(R.id.view1);
final View view2 = findViewById(R.id.view2);

// Setting up a spring animation to animate the view1 and view2 translationX and translationY properties
final SpringAnimation anim1X = new SpringAnimation(view1,
        DynamicAnimation.TRANSLATION_X);
final SpringAnimation anim1Y = new SpringAnimation(view1,
    DynamicAnimation.TRANSLATION_Y);
final SpringAnimation anim2X = new SpringAnimation(view2,
        DynamicAnimation.TRANSLATION_X);
final SpringAnimation anim2Y = new SpringAnimation(view2,
        DynamicAnimation.TRANSLATION_Y);

// Registering the update listener
anim1X.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() {

// Overriding the method to notify view2 about the change in the view1’s property.
    @Override
    public void onAnimationUpdate(DynamicAnimation dynamicAnimation, float value,
                                  float velocity) {
        anim2X.animateToFinalPosition(value);
    }
});

anim1Y.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() {

  @Override
    public void onAnimationUpdate(DynamicAnimation dynamicAnimation, float value,
                                  float velocity) {
        anim2Y.animateToFinalPosition(value);
    }
});

OnAnimationEndListener

OnAnimationEndListener notifies the end of an animation. You can set up the listener to receive callback whenever the animation reaches equilibrium or it is canceled. To register the listener, perform the following steps:

  1. Call the addEndListener() method and attach the listener to the animation.
  2. Override the onAnimationEnd() method to receive notification whenever an animation reaches equilibrium or is canceled.

Removing listeners

To stop receiving animation update callbacks and animation end callbacks, call removeUpdateListener() and removeEndListener() methods, respectively.

Setting animation start value

To set the start value of the animation, call the setStartValue() method and pass the start value of the animation. If you do not set the start value, the animation uses the current value of the view’s property as the start value.

Setting animation value range

You can set the minimum and the maximum animation values when you want to restrain the property value to a certain range. It also helps to control the range in case you animate properties that have an intrinsic range, such as alpha (from 0 to 1).

Both methods return the animation for which the value is being set.

Note: If you have set the start value and have defined an animation value range, ensure the start value is within the minimum and the maximum value range.

Setting start velocity

Start velocity defines the speed at which the animation property changes at the beginning of the animation. The default start velocity is set to zero pixel per second. You can set the velocity either with the velocity of touch gestures or by using a fixed value as the start velocity. If you choose to provide a fixed value, we recommend to define the value in dp per second and then convert it to pixel per second. Defining the value in dp per second allows velocity to be independent of density and form factors. For more information about converting value to pixel per second, refer to the Converting dp per second to pixel per second section.

To set the velocity, call the setStartVelocity() method and pass the velocity in pixel per second. The method returns the spring force object on which the velocity is set.

Note: Use the GestureDetector.OnGestureListener or the VelocityTracker class methods to retrieve and compute the velocity of touch gestures.

final View img = findViewById(R.id.imageView);
final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y);
…
// Compute velocity in the unit pixel/second
            vt.computeCurrentVelocity(1000);
            float velocity = vt.getYVelocity();
anim.setStartVelocity(velocity);

Converting dp per second to pixel per second

Velocity of a spring must be in pixel per second. If you choose to provide a fixed value as the start of the velocity, provide the value in dp per second and then convert it to pixel per second. For conversion, use the applyDimension() method from the TypedValue class. Refer to the following sample code:

float pixelPerSecond = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpPerSecond, getResources().getDisplayMetrics());

Setting spring properties

The SpringForce class defines the getter and the setter methods for each of the spring properties, such as damping ratio and stiffness. To set the spring properties, it is important to either retrieve the spring force object or create a custom spring force on which you can set the properties. For more information about creating a custom spring force, refer to the Creating a custom spring force section.

Tip: While using the setter methods, you can create a method chain as all the setter methods return the spring force object.

Damping ratio

The damping ratio describes a gradual reduction in a spring oscillation. By using the damping ratio, you can define how rapidly the oscillations decay from one bounce to the next. There are four different ways you can damp a spring:

To add the damping ratio to the spring, perform the following steps:

  1. Call the getSpring() method to retrieve the spring to add the damping ratio.
  2. Call the setDampingRatio() method and pass the damping ratio that you want to add to the spring. The method returns the spring force object on which the damping ratio is set.

    Note: The damping ratio must be a non-negative number. If you set the damping ratio to zero, the spring will never reach the rest position. In other words, it oscillates forever.

The following damping ratio constants are available in the system:

Figure 2: High bounce

Figure 3: Medium bounce

Figure 4: Low bounce

Figure 5: No bounce

The default damping ratio is set to DAMPING_RATIO_MEDIUM_BOUNCY.

final View img = findViewById(R.id.imageView);
final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y);
…
//Setting the damping ratio to create a low bouncing effect.
anim.getSpring().setDampingRatio(DAMPING_RATIO_LOW_BOUNCY);
…

Stiffness

Stiffness defines the spring constant, which measures the strength of the spring. A stiff spring applies more force to the object that is attached when the spring is not at the rest position. To add the stiffness to the spring, perform the following steps:

  1. Call the getSpring() method to retrieve the spring to add the stiffness.
  2. Call the setStiffness() method and pass the stiffness value that you want to add to the spring. The method returns the spring force object on which the stiffness is set.

    Note: The stiffness must be a non-negative number.

The following stiffness constants are available in the system:

Figure 6: High stiffness

Figure 7: Medium stiffness

Figure 8: Low stiffness

Figure 9: Very low stiffness

The default stiffness is set to STIFFNESS_MEDIUM.

final View img = findViewById(R.id.imageView);
final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y);
…
//Setting the spring with a low stiffness.
anim.getSpring().setStiffness(STIFFNESS_LOW);
…

Creating a custom spring force

You can create a custom spring force as an alternative to using the default spring force. The custom spring force lets you share the same spring force instance across multiple spring animations. Once you have created the spring force, you can set properties such as damping ratio and stiffness.

  1. Create a SpringForce object.

    SpringForce force = new SpringForce();

  2. Assign the properties by calling the respective methods. You can also create a method chain.

    force.setDampingRatio(DAMPING_RATIO_LOW_BOUNCY).setStiffness(STIFFNESS_LOW);

  3. Call the setSpring() method to set the spring to the animation.

    setSpring(force);

Starting animation

There are two ways you can start a spring animation: By calling the start() or by calling the animateToFinalPosition() method. Both the methods need to be called on the main thread.

animateToFinalPosition() method performs two tasks:

Since the method updates the final position of the spring and starts the animation if needed, you can call this method any time to change the course of an animation. For example, in a chained spring animation, the animation of one view depends on another view. For such an animation, it's more convenient to use the animateToFinalPosition() method. By using this method in a chained spring animation, you don't need to worry if the animation you want to update next is currently running.

Figure 10 illustrates a chained spring animation, where the animation of one view depends on another view.

Chained spring demo
Figure 10. Chained spring demo

To use the animateToFinalPosition() method, call the animateToFinalPosition() method and pass the rest position of the spring. You can also set the rest position of the spring by calling the setFinalPosition() method.

The start() method does not set the property value to the start value immediately. The property value changes at each animation pulse, which happens before the draw pass. As a result, the changes are reflected in the next view, as if the values are set immediately.

final View img = findViewById(R.id.imageView);
final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y);
…
//Starting the animation
anim.start();
…

Cancelling animation

You can cancel or skip to the end of the animation. An ideal situation where you need to cancel or skip to the end of the amiation is when a user interaction demands the animation to be terminated immediately. This is mostly when a user exits an app abruptly or the view becomes invisible.

There are two methods that you can use to terminate the animation. The cancel() method terminates the animation at the value where it is. Whereas, the canSkipToEnd() method skips the animation to the final value and then terminates it.

Before you can terminate the animation, it is important to first check the state of the spring. If the state is undamped, the animation can never reach the rest position. To check the state of the spring, call the canSkipToEnd() method. If the spring is damped, the method returns true, otherwise false.

Once you know the state of the spring, you can terminate an animation by using either skipToEnd() method or the cancel() method.The cancel() method must be called only on the main thread.

Note: In general, the skipToEnd() method causes a visual jump.

This site uses cookies to store your preferences for site-specific language and display options.

Hooray!

This class requires API level or higher

This doc is hidden because your selected API level for the documentation is . You can change the documentation API level with the selector above the left navigation.

For more information about specifying the API level your app requires, read Supporting Different Platform Versions.

Take a one-minute survey?
Help us improve Android tools and documentation.