ObjectAnimator

Tap on the screen to move the red disk. The entire screen, including the white background and the red disk, is one big object of class MyView. The disk is not an object at all. It is drawn by a call to drawCircle in the onDraw method of the MyView.

The MyView contains a field named center of class PointF, holding the coördinates of the center of the disk. When you tap the screen, we create an ObjectAnimator object that gradually changes the vaue of this property from its current value to the point where the finger touched. During the animation, the ObjectAnimator repeatedly calls the evaluate method of the TypeEvaluator object and the setCenter setter for the center field. See Animating with ObjectAnimator and Using a Type Evaluator.

If the property to be animated is an object (e.g., a PointF), the fourth argument of ObjectAnimator.ofObject must be a copy of the property. If the fourth argument were missing, the ObjectAnimator would also attempt to call a getCenter getter. In this case, an obscure bug would happen. The startValue passed to evaluate would constantly be updated to be the current value of the field, causing the field to reach its final value too soon.

The Animation app had a TranslateAnimation (SDK 1, subclass of Animation). This app has an ObjectAnimator (SDK 11, subclass of Animator). The previous app didn’t change the properties (x and y) of the moving drawable until the animation was finished. This app changes the properties while the animation is in progress, which makes more sense.

Source code in ObjectAnimator.zip

  1. MainActivity.java
  2. MyView.java
  3. activity_main.xml: unused.
  4. AndroidManifest.xml: untouched.
  5. build.gradle (Module: app)

ObjectAnimators in ApiDemos

  1. Animation/Bouncing Balls (Tap the screen to start the animations.)
    1. app/java/com.example.android.apis/animation/BouncingBalls.java
      Class BouncingBalls is a subclass of class Activity. It creates eight ObjectAnimators. The first one, colorAnim, uses an ArgbEvaluator instead of our PointFEvaluator. The remaining ObjectAnimators do not need any TypeEvauator objects at all, because the fields they animate are merely of type float. To make the animations happen one after another, the BouncingBalls.MyAnimationView object also puts five of the animations in an AnimatorSet, and two of them in another AnimatorSet.

    2. app/java/com.example.android.apis/animation/ShapeHolder.java
      Class ShapeHolder contains a ShapeDrawable, which is a subclass of Drawable.

    3. app/res/layout/bouncing_balls.xml
      The layout file contains an empty LinearLayout whose id is container.

  2. Animation/Cloning
    1. app/java/com.example.android.apis/animation/AnimationCloning.java
      Class AnimationCloning is a subclass of class Activity. Its nested class AnimationCloning.MyAnimationView creates four ObjectAnimators.

    2. app/java/com.example.android.apis/animation/ShapeHolder.java
      Class ShapeHolder contains a ShapeDrawable, which is a subclass of Drawable.

    3. app/res/layout/animation_cloning.xml
      The layout file contains a Button in a LinearLayout.

  3. Animation/Custom Evaluator
    1. app/java/com.example.android.apis/animation/CustomEvaluator.java
      Class CustomEvaluator is a subclass of class Activity. Its nested class CustomEvaluator.XYHolder is just like Android’s class PointF, and its nested class CustomEvaluator.XYEvaluator is just like our class PointFEvaluator.

    2. app/java/com.example.android.apis/animation/ShapeHolder.java
      Class ShapeHolder contains a ShapeDrawable, which is a subclass of Drawable.

    3. app/res/layout/animator_custom_evaluator.xml
      The layout file contains a Button.

  4. Animation/Events

Things to try

  1. Change the ObjectAnimator’s interpolator to AccelerateDecelerateInterpolator (the default).

  2. Listen for the end of the animation.
                            objectAnimator.addListener(new AnimatorListenerAdapter() {
                                @Override
                                public void onAnimationEnd(Animator animator) {
                                    Toast.makeText(getContext(), "onAnimationEnd", Toast.LENGTH_LONG).show();
                                }
                            });
    

  3. Animate the backgroundColor of the MyView instead of its center. Replace the ObjectAnimator with the following. You can remove class PointFEvaluator.
                            ObjectAnimator objectAnimator = ObjectAnimator.ofInt(
                                MyView.this,
                                "backgroundColor",
                                Color.YELLOW //end value
                            );
    
                            objectAnimator.setEvaluator(new ArgbEvaluator());
    			objectAnimator.setDuration(1000L); //milliseconds
                            objectAnimator.start();
    
    Change the orientation of the device (portrait to landscape) to destroy and re-create the Activity object, and with it the MyView object.

  4. Animate the backgroundColor and center of the MyView simultaneously. Replace the ObjectAnimator with the following.
                            ObjectAnimator centerAnimator = ObjectAnimator.ofObject(
                                MyView.this,
                                "center",   //name of field
                                new PointFEvaluator(),
                                new PointF(center.x, center.y),                    //start value
                                new PointF(motionEvent.getX(), motionEvent.getY()) //end value
                            );
    
                            ObjectAnimator backgroundColorAnimator = ObjectAnimator.ofInt(
                                MyView.this,
                                "backgroundColor",
                                Color.YELLOW //end value
                            );
                            backgroundColorAnimator.setEvaluator(new ArgbEvaluator());
    
                            AnimatorSet animatorSet = new AnimatorSet();
                            animatorSet.setDuration(3000L); //milliseconds
                            animatorSet.playTogether(centerAnimator, backgroundColorAnimator);
                            animatorSet.start();
    

  5. Do the two animations one at a time.
                            AnimatorSet animatorSet = new AnimatorSet();
                            animatorSet.setDuration(3000L); //milliseconds
                            animatorSet.playSequentially(centerAnimator, backgroundColorAnimator);
                            animatorSet.start();