ViewPropertyAnimator

Tap the screen and watch the red disk move. The white area is a BackgroundView object, and the disk is a LittleView object. (Actually, the LittleView is more than just the disc. It is the square area that just barely encloses the disk.) The BackgroundView imposes a size and initial position on the LittleView.

A View object has methods named getX and setX. We summarize this by saying that a View object has a property named x. Think of the property as a private field, and the getX and setX as its getter and setter. A View object has 12 properties that can be animated with a ViewPropertyAnimator:

property getter setter animator animator by
alpha getAlpha setAlpha alpha alphaBy
rotation getRotation setRotation rotation rotationBy
rotationX getRotationX setRotationX rotationX rotationXBy
rotationY getRotationY setRotationY rotationY rotationYBy
scaleX setScaleX getScaleX scaleX scaleXBy
scaleY setScaleY getScaleY scaleY scaleYBy
translationX getTranslationX setTranslationX translationX translationXBy
translationY getTranslationY setTranslationY translationY translationYBy
translationZ getTranslationZ setTranslationZ translationZ translationZBy
x getX setX x xBy
y getY setY y yBy
z getZ setZ z zBy

The BackgroundView is touch sensitive because we plugged a View.OnTouchListener into it. The LittleView moves because the View.OnTouchListener plugs a ViewPropertyAnimator into the LittleView. The ViewPropertyAnimator gradually changes the x and y properties of the LittleView during a three-second interval. (It changes translationX but not getLeft.) See Animating with ViewPropertyAnimator and Introducing ViewPropertyAnimator.

Source code in ViewPropertyAnimator.zip

  1. MainActivity.java
  2. Class BackgroundView
    1. BackgroundView.java. Class BackgroundView calls addView, so it must be a subclass of ViewGroup such as RelativeLayout. Even though it is a View, class BackgroundView does not need a onDraw method.
    2. res/layout/sample_background_view.xml
    3. res/values/attrs_background_view.xml
  3. Class LittleView
    1. LittleView.java. The onLayout method of the LittleView is called when the LittleView is created, and when the BackgroundView calls the layout method of the LittleView.
    2. res/layout/sample_little_view.xml
    3. res/values/attrs_little_view.xml
  4. activity_main.xml: unused.
  5. AndroidManifest.xml
  6. build.gradle (Module: app)

Create the project

Create the two subclasses of class View named BackgroundView and LittleView. Edit BackgroundView.java and change the superclass from View to RelativeLayout.

This is our first app to have more than one user-defined subclass of class View. In the file res/values/attrs_little_view.xml, rename the four resources to exampleString1, exampleDimension1, etc. This will remove the conflict with the four resources named exampleString, exampleDimension, etc., in the file res/values/attrs_background_view.xml.

If you don’t rename the resources and you want to see the “Duplicate resources” error messages, click on Gradle Console in the lower right corner of Android Studio.

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:mergeDebugResources'.
> [attr/exampleColor] /Users/myname/AndroidStudioProjects/ViewPropertyAnimator/app/src/main/res/values/attrs_background_view.xml	[attr/exampleColor] /Users/myname/AndroidStudioProjects/ViewPropertyAnimator/app/src/main/res/values/attrs_little_view.xml: Error: Duplicate resources
  [attr/exampleDimension] /Users/myname/AndroidStudioProjects/ViewPropertyAnimator/app/src/main/res/values/attrs_background_view.xml	[attr/exampleDimension] /Users/myname/AndroidStudioProjects/ViewPropertyAnimator/app/src/main/res/values/attrs_little_view.xml: Error: Duplicate resources
  [attr/exampleDrawable] /Users/myname/AndroidStudioProjects/ViewPropertyAnimator/app/src/main/res/values/attrs_background_view.xml	[attr/exampleDrawable] /Users/myname/AndroidStudioProjects/ViewPropertyAnimator/app/src/main/res/values/attrs_little_view.xml: Error: Duplicate resources
  [attr/exampleString] /Users/myname/AndroidStudioProjects/ViewPropertyAnimator/app/src/main/res/values/attrs_background_view.xml	[attr/exampleString] /Users/myname/AndroidStudioProjects/ViewPropertyAnimator/app/src/main/res/values/attrs_little_view.xml: Error: Duplicate resources

Things to try

  1. In onTouch, you can telescope
                            //Start two animations simultaneously.
                            viewPropertyAnimator.x(newX);
                            viewPropertyAnimator.y(newY);
    
    to
                            //Start two animations simultaneously.
                            viewPropertyAnimator.x(newX).y(newY);
    

  2. Make circle in the LittleView green during the animation, and change it back to red when the animation is over. Add the following method to class LittleView.
        public void setPaintColor(int color) {
            paint.setColor(color);
        }
    
    Insert an Animator.AnimatorListener into the ViewPropertyAnimator before starting the animations. An AnimatorListenerAdapter is an Animator.AnimatorListener with all of its methods implemented as stubs. This means that we have to override only the two methods we’re interested in overriding, not all four of them.
                            viewPropertyAnimator.setListener(new AnimatorListenerAdapter() {
                                @Override
                                public void onAnimationStart(Animator animation) {
                                    littleView.setPaintColor(Color.GREEN);
                                    littleView.invalidate();
                                }
    
                                @Override
                                public void onAnimationEnd(Animator animation) {
                                    littleView.setPaintColor(Color.RED);
                                    littleView.invalidate();
                                }
                            });
    

  3. Make the LittleView fade out during the first animation. Change
                            //Start two animations simultaneously.
                            viewPropertyAnimator.x(newX).y(newY);
    
    to
                            //Start three animations simultaneously.
                            viewPropertyAnimator.x(newX).y(newY).alpha(0f);
    
    If you think it’s clearer, you can write it as three separate statements:
                            //Start three animations simultaneously.
                            viewPropertyAnimator.x(newX);
                            viewPropertyAnimator.y(newY);
                            viewPropertyAnimator.alpha(0f);
    
    Change the orientation of the device to destroy and re-create the Activity object, which will destroy and re-create the Views with their default alphas.

  4. Make the LittleView grow during the first animation. Change
                            //Start two animations simultaneously.
                            viewPropertyAnimator.x(newX).y(newY);
    
    to
                            //Start four animations simultaneously.
                            viewPropertyAnimator.x(newX).y(newY).scaleX(2f).scaleY(2f);
    

  5. Make the LittleView grow a bit during each animation. Shorten the duration for a snappier animation. Tap the center of the disk.
                            //Start four animations simultaneously.
                            viewPropertyAnimator.x(newX).y(newY).scaleXBy(.1f).scaleYBy(.1f);
    

  6. Give the LittleView a dashed outline so we can see that it’s really a square. Each dash is 10 pixels long, followed by a five pixel gap.
        //an additional field for class LittleView
        private Paint outlinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    
            //in the LittleView constructor
            outlinePaint.setColor(Color.BLACK);
            outlinePaint.setStyle(Paint.Style.STROKE);   //vs. FILL
            outlinePaint.setStrokeWidth(0f);   //0f for hairline (1 pixel)
            DashPathEffect dashPathEffect = new DashPathEffect(new float[] {10f, 5f}, 0f);
            outlinePaint.setPathEffect(dashPathEffect);
    
            //in the LittleView onDraw, immediately before the translate
            Rect outline = canvas.getClipBounds(); //the rectangular boundary of the canvas
            canvas.drawRect(outline, outlinePaint);
    

  7. Now that we can see that the LittleView is really a square, make it tumble during each animation.
                            //Start three animations simultaneously.
                            viewPropertyAnimator.x(newX).y(newY).rotationBy(45f);	//degrees clockwise
    

  8. Rotate the LittleView in three dimensions around its vertical axis (the Y axis). Its left edge will move towards you, and its right edge away.
                            //Start three animations simultaneously.
                            viewPropertyAnimator.x(newX).y(newY).rotationYBy(180f); //counterclockwise when viewed from above