12.1: Animations

Contents:

What is animation?

Animation is the technique for creating the illusion of a moving object by showing a series of discrete images that change over time, such as:

  • A flip book, which has a different image on each page. By flipping through the pages fast enough, your eyes perceive it as motion.
  • Claymation, which is a type of stop-motion animation.
  • User interface animations, such as flinging a list item to move it off the screen.
  • .. and millions of mobile games with character, environment, and UI animations.

Each image in an animated sequence is called a frame . The speed at which those images appear on the screen is called the frame rate . Ideally, your frame rate closely matches the screen's refresh rate.

  • If the frame rate is slower than the refresh rate, animation may stutter.
  • If the frame rate is faster than the refresh rate, the app is wasting resources.
  • If the frame rate is the same as the screen refresh rate, animations are smooth and no resources are wasted.

Fortunately, the Android system manages frame rate for you, and in most situations, you do not need to manage the frame rate of your animations. If you want to go deep, see the Graphics Architecture series of articles for an in-depth explanation of how the Android framework draws to the screen.

Types of animation for Android

The Android framework provides the following animation systems:

View animation

View animation, as the name implies, is a system for animating views. It is an older system and limited to View objects. It is relatively easy to set up and offers enough capabilities to meet many applications' needs.

Property animation

Introduced in Android 3.0 (API level 11), the property animation system lets you animate properties of any object, including ones that are not rendered to the screen. The system is extensible and lets you animate properties of custom types as well. Prefer property animation over View animation. See also the Property Animation practical.

Drawable animation

Drawable animation involves displaying Drawable resources one after another, like a roll of film. This method of animation is useful if you want to animate things that are easier to represent with Drawable resources, such as a progression of bitmaps.

Physics-based animation

Physics-based animation relies on the laws of physics to manifest a high degree of realism in animation. Physics-based animation uses the fundamentals of physics to build animations. For example, an animation is driven by force, and the animation comes to rest when the force reaches equilibrium.

View animation

The View animation system provides the limited capability to only animate View objects. For example, you can scale or rotate a View object.

The view animation system only modifies where the view is drawn, and not the actual View object itself. For instance, if you animate a button to move across the screen, the button draws correctly, but the location where you can click the button does not change, and you have to implement your own logic to handle this.

The view animation system, however, takes less time to set up and requires less code to write than property animations. If view animation accomplishes everything that you need to do, there may be no need to use the property animation system.

Property animation

The property animation system is a robust framework that allows you to animate almost anything. A property animation changes a property's value over a specified length of time. For example, you can animate a circle to grow bigger by increasing its radius over time. You can define an animation to change any object property (a field in an object) over time, regardless of whether the change draws to the screen or not.

With the property animation system, at a high level, you assign animators to the properties that you want to animate, such as color, position, or size. You also define aspects of the animation, such as interpolation. For example, you could create an animator for the radius of a circle you want to grow.

The property animation system lets you define the following characteristics of an animation:

  • Duration: You can specify how long an animation runs. The default length is 300 milliseconds.
  • Time interpolation: You can specify how the values for the property are calculated as a function of the animation's current elapsed time. For example, you can move an object across the screen linearly, by the same amount for every time interval. Or you can increase or decrease the amount for every interval. You can choose from system-provided interpolators or create your own. See below for details.
  • Repeat count and behavior: You can specify whether or not to have an animation repeat when it reaches the end of a duration, and how many times to repeat the animation. You can also specify whether you want the animation to play back in reverse. Setting it to reverse plays the animation forwards then backwards repeatedly, until the number of repeats is reached.
  • Animator sets: You can group animations into logical sets that play together or sequentially or after specified delays. For example, you could coordinate several bouncing balls.
  • Frame-refresh delay: You can specify how often to refresh frames of your animation. The default is set to refresh every 10 ms, but the speed in which your application can refresh frames ultimately depends on how busy the system is overall and how fast the system can service the underlying timer.

Interpolators

Material Design encourages vivid animations that catch the user's attention while behaving in a more natural way. In nature, most motion is not linear but changes over time. For example, friction will slow down a rolling ball, or a vehicle gains speed as it moves forward.

A time interpolator defines how specific values in an animation change over time. For example, you can specify animations to happen linearly across the whole animation, meaning the animation moves evenly the entire time. You can also specify animations to use nonlinear time, for example, accelerating at the beginning and decelerating at the end of the animation.

The following interpolators are predefined in the Android API and ready to use:

  • LinearInterpolator: An interpolator whose rate of change is constant. The value changes at a constant rate over time. For example, you can move a box across the screen, taking a total time of three seconds, and every frame moves the box by the same amount of distance.
  • AccelerateInterpolator: An interpolator whose rate of change starts out slowly and then accelerates. The value changes at an increasing or decreasing rate over time. For example, you can move a box across the screen, taking a total time of three seconds, and every frame moves the box by an increasing or decreasing amount of distance, creating an impression accelerating or decelerating.
  • AccelerateDecelerateInterpolator: An interpolator whose rate of change starts and ends slowly but accelerates through the middle. For example, you can start a box moving at one end of the screen, let it accelerate, and come to slow stop at the other side of the screen.
  • AnticipateInterpolator: An interpolator whose change starts backward then flings forward. Visualize this by thinking of snapping a rubber band.
  • OvershootInterpolator: An interpolator whose change flings forward and overshoots the last value then comes back.
  • AnticipateOvershootInterpolator: An interpolator whose change starts backward, flings forward and overshoots the target value, then finally goes back to the final value.
  • BounceInterpolator: An interpolator whose change bounces at the end.
  • CycleInterpolator: An interpolator whose animation repeats for a specified number of cycles.
  • DecelerateInterpolator: An interpolator whose rate of change starts out quickly and and then decelerates.
  • PathInterpolator: An interpolator that follows a Path that you specify.
  • TimeInterpolator: An interface that allows you to implement your own interpolator.

Creating a property animation

To animate the property of an object, you always need the following:

  • An Animator that manages the animation for you. The Animator class provides the basic structure for creating animations. You normally do not use the Animator class directly, because it only provides minimal functionality that must be extended to fully support animating values. The ObjectAnimator subclass does a lot of work for you. For example, ObjectAnimator updates the property accordingly when it computes a new value for the animation. Most of the time, use ObjectAnimator.
  • A TypeEvaluator. Evaluators tell the property animation system how to calculate values for a given property. They take the timing data that is provided by an Animator class, the animation's start and end value, and calculate the animated values of the property based on this data. You can use one of the provided IntEvaluator, FloatEvaluator, or ArgbEvaluator classes, or you can subclass TypeEvaluator to handle other types of data.
  • A TimeInterpolator. You can use one of the provided interpolators listed above, such as AccelerateInterpolator, or you can create your own subclass of TimeInterpolator.

To create a basic property animation with ObjectAnimator:

  1. Create an instance of ObjectAnimator. Choose the factory method and supply the appropriate arguments:

    • The object that is to be animated. This can be a View or any other object, including a custom object with custom properties.
    • The name of the property to be animated as a string.
    • A starting value.
    • The ending value.

    The following example uses the ObjectAnimator class's ofFloat() factory method. The ofFloat() method animates the radius property of a custom view (called mView) from 0 to 50.

    ObjectAnimator animator = ObjectAnimator.ofFloat(mView,"radius", 0, 50);
    
  2. Optionally, set an interpolator.
     animator.setInterpolator(new AccelerateInterpolator());
    
  3. Specify the duration of your animation in milliseconds.
     animator.setDuration(400);
    
  4. Start the animation.
     animator.start();
    

    Required setter for the animated property

To make sure that the ObjectAnimator object correctly updates properties:

  • The object property that you are animating must have a "setter" function in the form of set PropertyName () of a matching type. The ObjectAnimator automatically updates the property during animation, so the ObjectAnimator must be able to access the property by using this setter method. For example, if the property name is radius, you need a setRadius() method.
  • If you only specify an ending value for the animation, you need a "getter" function, which must be in the form of get PropertyName () of a matching type. For example, if the property name is radius, you need a getRadius() method.
  • Depending on what property or object you are animating, you might need to call the invalidate() method on a View to force the View to redraw itself with the updated animated values. You call invalidate() in the onAnimationUpdate() callback. For example, animating the color property of a Drawable object only causes updates to the screen when that Drawable object redraws itself. All of the property setters on views, such as setAlpha() and setTranslationX(), invalidate the View properly, so you do not need to invalidate the View when calling these methods with new values.

To learn more about what you can do with property animation, see the Property Animation documentation.

Animation listeners

For even more control over your animations, you can listen for important events during the animation process. For example, to do something after an animation ends, add a listener and callback for onAnimationEnd().

ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
fadeAnim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
    balls.remove(((ObjectAnimator)animation).getTarget());
}

See the AnimationListener documentation for details.

Choreographing multiple animations with an AnimatorSet object

In many cases, you want to group animations together so that they run in relation to one another. For example, you might play an animation when another animation starts or finishes. The Android system lets you bundle animations together into an AnimatorSet object. The AnimatorSet lets you specify whether to start animations simultaneously, sequentially, or after a specified delay. You can also nest AnimatorSet objects within each other, as shown in the code below. The animations are played in the following order:

  1. Play bounceAnim.
  2. Play squashAnim1, squashAnim2, stretchAnim1, and stretchAnim2 at the same time.
  3. Play bounceBackAnim.
  4. Play fadeAnim.

Here is the code:

// Create a new AnimatorSet.
AnimatorSet bouncer = new AnimatorSet();

// Specify when animations play relative to each other.
bouncer.play(bounceAnim).before(squashAnim1);
bouncer.play(squashAnim1).with(squashAnim2);
bouncer.play(squashAnim1).with(stretchAnim1);
bouncer.play(squashAnim1).with(stretchAnim2);
bouncer.play(bounceBackAnim).after(stretchAnim2);

// Create a fade animation
ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);

// Create second animator set that specifies to play the bouncer animation set
// before the fade animation. 
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(bouncer).before(fadeAnim);
animatorSet.start();

See the AnimatorSet documentation for more information.

Property animations in XML

The property animation system lets you declare property animations with XML instead of doing it programmatically. By defining your animations in XML, you can reuse your animations in multiple activities.

Save the XML files for property animations in the res/animator/ directory.

The following property animation classes have XML declaration support with the following XML tags:

Class XML tag
ValueAnimator animator
ObjectAnimator objectAnimator
AnimatorSet set

To find the attributes that you can use in your XML declaration, see Animation Resources. The following example plays the two sets of object animations sequentially. The first nested set plays two object animations together:

<set android:ordering="sequentially">
    <set>
        <objectAnimator
            android:propertyName="x"
            android:duration="500"
            android:valueTo="400"
            android:valueType="intType"/>
        <objectAnimator
            android:propertyName="y"
            android:duration="500"
            android:valueTo="300"
            android:valueType="intType"/>
    </set>
    <objectAnimator
        android:propertyName="alpha"
        android:duration="500"
        android:valueTo="1f"/>
</set>

In order to run this animation, you must inflate the XML resources in your code to an AnimatorSet object, then set the target objects for all of the animations, and then start the animation set. Call the setTarget() method to set a single target object for all children of the AnimatorSet, as a convenience. The following code shows how to do this:

AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
    R.anim.property_animator);
set.setTarget(myObject);
set.start();

Drawable animation

Drawable animation lets you load a series of Drawable resources one after another to create an animation. This is a traditional animation in the sense that it is created with a sequence of different images, played in order, like a roll of film.

The easiest way to create drawable animations is from an XML file. Save the file in res/drawable.

The XML file consists of an <animation-list> element as the root node and a series of child <item> nodes that each define a frame: a drawable resource for the frame and the frame duration. Here's an example XML file for a Drawable animation:

<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="true">
    <item android:drawable="@drawable/rocket_thrust1" android:duration="200" />
    <item android:drawable="@drawable/rocket_thrust2" android:duration="200" />
    <item android:drawable="@drawable/rocket_thrust3" android:duration="200" />
</animation-list>

This animation runs for three frames. With the android:oneshot attribute of the list to true, it will cycle just once then stop and hold on the last frame. If android:oneshot is set false, the animation will loop. With this XML saved as rocket_thrust.xml in the res/drawable/ directory of the project, it can be added as the background image to a View and then called to play. Here's an example activity, in which the animation is added to an ImageView object and animated when the screen is touched:

AnimationDrawable rocketAnimation;

public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);

  ImageView rocketImage = (ImageView) findViewById(R.id.rocket_image);
  rocketImage.setBackgroundResource(R.drawable.rocket_thrust);
  rocketAnimation = (AnimationDrawable) rocketImage.getBackground();
}

public boolean onTouchEvent(MotionEvent event) {
  if (event.getAction() == MotionEvent.ACTION_DOWN) {
    rocketAnimation.start();
    return true;
  }
  return super.onTouchEvent(event);
}

See Drawable Animation for more information.

Physics-based animation

Physics-based animation relies on the laws of physics to manifest a high degree of realism in animation. In our day-to-day life, when a change occurs, it comes with a physical transition that is natural for us to recognize.  Physics-based spring animation

Physics-based animations are driven by force instead of being driven by fixed durations and changes in animation values. The animation comes to rest when the force reaches equilibrium. This results in more natural looking animations and the ability to change an animation during its run without introducing visual disruption.

In summary, physics-based animations have these benefits:

  • Natural-looking. Physics-based animations are flexible and mimic real time movements. Drawing influence from physics creates motion that is easy to understand and works holistically.
  • Course correction. Animations keep momentum when their target changes, and end with a smoother motion.
  • Reduced visual janks. Animations appear more responsive and smooth, and reduce overall visual disruptions.  Animation where target changes, built by using <code>ObjectAnimator</code>

     Animation with changing target, built by using physics-based APIs

Creating a physics-based animation

The Android framework supports physics-based animations through the android.support.animation API, which was introduced with version 25.3.0 of the Android Support Library. To add the physics-based support library to your project, open the build.gradle file of your application and add the library to the dependencies section, replacing the N placeholder in the dependency shown below with the current version number:

dependencies {
    ...
    compile "com.android.support:support-dynamic-animation:N"
}

As of this writing, the library has classes for spring and fling animations.

  • Spring animation. In a spring-based animation, you customize the spring's stiffness, its damping ratio, and its final position. When 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. A spring is the obvious example for this.  Example of spring animation

  • Fling animation. Fling-based animation uses a friction force that is proportional to an object's velocity. Use it to animate a property of an object when you want to end the animation gradually. It has an initial momentum, which is mostly received from the gesture velocity, and gradually slows down. The animation comes to an end when the velocity of the animation is low enough that it makes no visible change on the device screen.  Example of fling animation

Here is a code snippet for a simple vertical spring animation:

final SpringAnimation anim = new SpringAnimation(this, DynamicAnimation.Y, 10)
   .setStartVelocity(10000);
anim.getSpring().setStiffness(STIFFNESS_LOW);
anim.start();

See the Spring Animation documentation and SpringAnimation class for more information.

Here is a code snippet for a simple rotation fling animation:

FlingAnimation fling = new FlingAnimation(this, DynamicAnimation.ROTATION_X);
fling.setStartVelocity(150)
       .setMinValue(0)
       .setMaxValue(1000)
       .setFriction(0.1f)
       .start();

See the Fling Animation documentation and FlingAnimation class for more information.

The related exercises and practical documentation is in Advanced Android – Practicals:

Learn more

Android developer docs:

results matching ""

    No results matching ""