This codelab is part of the Advanced Android Development training course, developed by the Google Developers Training team. You will get the most value out of this course if you work through the codelabs in sequence.

For complete details about the course, see the Advanced Android Development overview.

Introduction

The Property Animation system allows you to animate almost any property of an object. 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. 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.

With the property animation system, 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 would create an animator for the radius of a circle whose size you want to change.

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

What you should already know

You should be able to:

What you'll learn

What you'll do

The PropertyAnimation app shows a white screen when it opens. When the user taps the screen, an animation plays. The animation draws an expanding circle, then pauses. Then the animation draws a shrinking circle that changes color. Finally, the animation draws the same circle again, reversing without pausing. The screenshot below shows a snapshot of the PropertyAnimation app during animation.

Note that in this advanced practical, you are expected to create member variables, import classes, and extract values as needed.

1.1 Create an app

  1. Create an app that uses the Empty Activity template. Make sure that Backwards Compatibility and Generate Layout File are enabled.

1.2 Create the custom view to animate

  1. Create a new custom view class called PulseAnimationView that extends View.
public class PulseAnimationView extends View {}
  1. Add two two required constructors. When you create your custom view from code exclusively, you only need the first constructor. When you inflate your custom view from XML, the system calls the second constructor and if it's missing, you get an error.
public PulseAnimationView(Context context) {this(context, null);}

public PulseAnimationView(Context context, AttributeSet attrs) {
   super(context, attrs);
}
  1. In activity_main.xml, remove the TextView and add a PulseAnimationView that matches the size of the parent.
<com.example.android.propertyanimation.PulseAnimationView
   android:layout_width="match_parent"
   android:layout_height="match_parent"/>
  1. Run your app. It shows a white screen and the name of the app.

1.3 Implement the method to set the radius

This app uses a property animator, which changes a property's value over a specified length of time. You will change the radius property of the PulseAnimationView to animate a circle by changing its size.

The property animator needs to be able to change the property that will be animated. It does this through a "setter" method for the property. In order for the animator to find and use the setter, the following conditions need to be met:

  1. Create a member variable for the radius in PulseAnimationView.
private float mRadius;
  1. Create a public void setRadius() method that takes a float radius as its argument. Set mRadius to the passed-in radius and call the invalidate() method.
public void setRadius(float radius) {
   mRadius = radius;
   invalidate();
}

To make the animation more interesting, use the radius to affect other aspects of the animation. For example, you could play a sound as the circle grows, and the sound could change as a function of the radius. For the PropertyAnimation app, in addition to changing the size, you are going to change the color of the circle as a function of the radius.

  1. Create and initialize a mPaint member variable.
private final Paint mPaint = new Paint();
  1. Create a constant COLOR_ADJUSTER and set it to 5. You will use this constant in the next step.
private static final int COLOR_ADJUSTER = 5;
  1. Inside the setRadius() method, after setting mRadius and before calling the invalidate() method, change the color of the mPaint variable. Colors are integers and can thus be used in integer operations. You can change the value of the COLOR_ADJUSTER constant to see how it affects the color of the circle. You can also use a more sophisticated color function, if you want to.
mPaint.setColor(Color.GREEN + (int) radius / COLOR_ADJUSTER);

1.4 Add code to respond to touch events

In the PropertyAnimation app, animation is initiated by a user touch, and the animation originates at the location of the touch event.

  1. In the custom view class, create private float member variables mX and mY to store the event coordinates.
private float mX;
private float mY;
  1. Override the onTouchEvent() method to get the event coordinates and store them in the mX and mY variables.
@Override
public boolean onTouchEvent(MotionEvent event) {
   if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
       mX = event.getX();
       mY = event.getY();
   }
   return super.onTouchEvent(event);
}

1.5 Add the animation code

The animation is performed by an Animator object that, once started, changes the value of a property from a starting value towards an end value over a given duration.

  1. Create class constants for the animation duration and for a delay before the animation starts. You can change the values of these constants later and explore how that affects the appearance of the animation. The time is in milliseconds.
private static final int ANIMATION_DURATION = 4000;
private static final long ANIMATION_DELAY = 1000;
  1. Override the onSizeChanged() method.
@Override
public void onSizeChanged(int w, int h, int oldw, int oldh) {}

Inside the onSizeChanged() method, you will create three ObjectAnimator objects and one AnimatorSet object. You cannot create them in the onCreate() method, because the views have not been inflated, and so the call to getWidth() used below would not return a valid value.

  1. In the onSizeChanged() method, create an ObjectAnimator called growAnimator. You need to pass in a reference to the object that is being animated (this), the name of the property that is to be animated ("radius"), the starting value (0), and the ending value (getWidth()). In this case, the ending value is the width of the PulseAnimationView.
ObjectAnimator growAnimator = ObjectAnimator.ofFloat(this,
       "radius", 0, getWidth());
  1. Set the duration of the animation in milliseconds.
growAnimator.setDuration(ANIMATION_DURATION);
  1. Choose an interpolator for the animation. The interpolator affects the rate of change; that is, the interpolator affects how the animated property changes from its starting value to its ending value.
growAnimator.setInterpolator(new LinearInterpolator());
  1. Create a second ObjectAnimator object named shrinkAnimator. Use the same parameters as for growAnimator but swap the start and end values.
ObjectAnimator shrinkAnimator = ObjectAnimator.ofFloat(this,
       "radius", getWidth(), 0);
  1. Set the duration to ANIMATION_DURATION and use a LinearOutSlowInInterpolator. This is a more complex interpolator and you can check the documentation for details.
shrinkAnimator.setDuration(ANIMATION_DURATION);
shrinkAnimator.setInterpolator(new LinearOutSlowInInterpolator());
  1. Add a starting delay. When the animation is started, it will wait for the specified delay before it runs.
shrinkAnimator.setStartDelay(ANIMATION_DELAY);
  1. Still in onSizeChanged(), create a third ObjectAnimator instance called repeatAnimator.
ObjectAnimator repeatAnimator = ObjectAnimator.ofFloat(this,
       "radius", 0, getWidth());
repeatAnimator.setStartDelay(ANIMATION_DELAY);
repeatAnimator.setDuration(ANIMATION_DURATION);
  1. Add a repeat count to repeatAnimator. A repeat count of 0 is the default. With a repeat count of 0, the animation plays once and does not repeat. With a repeat count of 1, the animation plays twice.
repeatAnimator.setRepeatCount(1);
  1. Set the repeat mode to REVERSE. In this mode, every time the animation plays, it reverses the beginning and end values. (The other possible value, which is the default, is RESTART.)
repeatAnimator.setRepeatMode(ValueAnimator.REVERSE);
  1. Create a private AnimatorSet member variable called mPulseAnimatorSet and initialize the variable with an AnimatorSet.
private AnimatorSet mPulseAnimatorSet = new AnimatorSet();

An AnimatorSet allows you to combine several animations and to control in what order they are played. You can have several animations play at the same time or in a specified sequence. AnimatorSet objects can contain other AnimatorSet objects. See the Property Animation guide for all the cool things you can do with animator sets.

  1. The following AnimatorSet is very simple and specifies that the growAnimator should play before the shrinkAnimator, followed by the repeatAnimator. Add it after you have created the animators.
mPulseAnimatorSet.play(growAnimator).before(shrinkAnimator);
mPulseAnimatorSet.play(repeatAnimator).after(shrinkAnimator);
  1. If you run your app now, you still only see the white screen.

1.6 Add code to draw the circle

The Animator that you implemented does not draw anything. The actual drawing of the circle must be done in the onDraw() method, which is executed after the view has been invalidated, which happens in the setRadius() method.

  1. Override the onDraw() method to draw a circle at the mX, mY coordinates.
  2. Give the circle a radius of mRadius and set the color to mPaint.
@Override
protected void onDraw(Canvas canvas) {
   super.onDraw(canvas);
   canvas.drawCircle(mX, mY, mRadius, mPaint);
}

1.7 Play the animation

  1. In the onTouchEvent() method, add code to play the animation if there is an ACTION_DOWN event. If an animation is running, cancel it. This resets the mPulseAnimatorSet and its animations to the starting values.
if(mPulseAnimatorSet != null && mPulseAnimatorSet.isRunning()) {
   mPulseAnimatorSet.cancel();
}
mPulseAnimatorSet.start();
  1. Run your app and tap the white screen to see the animations play. Have some fun and experiment with the animation!

Android Studio project: PropertyAnimation.

Write an app that demonstrates the use of the physics-based animation from the support library.

dependencies {
    ...
    compile "com.android.support:support-dynamic-animation:26.0.0"
}
final SpringAnimation anim = new SpringAnimation(
    this, DynamicAnimation.Y, 10)
   .setStartVelocity(10000);
anim.getSpring().setStiffness(STIFFNESS_LOW);
anim.start();
FlingAnimation fling = new FlingAnimation(this, DynamicAnimation.ROTATION_X);
fling.setStartVelocity(150)
       .setMinValue(0)
       .setMaxValue(1000)
       .setFriction(0.1f)
       .start();

With property animation, you can use almost any property of an object to create an animation.

Here's one way to create a property animation:

Other information about property animations:

See the PropertyAnimation guide for a complete description of all the cool things you can do with property animations.

The related concept documentation is in 12.1 Animations.

Android developer documentation:

This section lists possible homework assignments for students who are working through this codelab as part of a course led by an instructor. It's up to the instructor to do the following:

Instructors can use these suggestions as little or as much as they want, and should feel free to assign any other homework they feel is appropriate.

If you're working through this codelab on your own, feel free to use these homework assignments to test your knowledge.

Build and run an app

Create an app that uses non-trivial property animation. For example, animate multiple properties, animate multiple objects, or create complex animations by using animator sets. Below are some ideas.

Answer these questions

Question 1

What types of animations are available with Android?

Question 2

Which of the following statements about property animation are true?

Question 3

What are the advantages of using physics-based animation libraries? Select up to three answers.

Submit your app for grading

Guidance for graders

Check that the app has the following features:

To see all the codelabs in the Advanced Android Development training course, visit the Advanced Android Development codelabs landing page.