Animation - Android Application Development: A Beginner's Tutorial (2015)

Android Application Development: A Beginner's Tutorial (2015)

Chapter 15. Animation

Animation is an interesting feature in Android that has been available since the very beginning (API Level 1). In this chapter you will learn to use an Animation API called property animation, which was added to Honeycomb (API Level 11). The new API is more powerful than the previous animation technology called view animation. You should use property animation in new projects.

Overview

The Property Animation API consists of types in the android.animation package. The old animation API, called view animation, resides in the android.view.animation package. This chapter focuses on the new animation API and does not discuss the older technology. It also does not discuss drawable animation, which is the type of animation that works by loading a series of images, played one after another like a roll of film. For more information on drawable animation, see the documentation for android.graphics.drawable.AnimationDrawable.

Property Animation

The powerhouse behind property animation is the android.animation.Animator class. It is an abstract class, so you do not use this class directly. Instead, you use one of its subclasses, either ValueAnimator or ObjectAnimator, to create an animation. In addition, the AnimatorSet class, another subclass of Animator, is designed to run multiple animations in parallel or sequentially.

All these classes reside in the same package and this section looks at these classes.

Animator

The Animator class is an abstract class that provides methods that are inherited by subclasses. There is a method for setting the target object to be animated (setTarget), a method for setting the duration (setDuration), and a method for starting the animation (start). The start method can be called more than once on an Animator object.

In addition, this class provides an addListener method that takes an Animator.AnimatorListener instance. The AnimatorListener interface is defined inside the Animator class and provides methods that will be called by the system upon the occurrence of certain events. You can implement any of these methods if you want to respond to a certain event.

The following are methods in AnimatorListener.

void onAnimationStart(Animator animation);

void onAnimationEnd(Animator animation);

void onAnimationCancel(Animator animation);

void onAnimationRepeat(Animator animation);

For example, the onAnimationStart method is called when the animation starts and the onAnimationEnd method is called when it ends.

ValueAnimator

A ValueAnimator creates an animation by calculating a value that transitions from a start value and to an end value. You specify what the start value and end value should be when constructing the ValueAnimator. By registering an UpdateListener to a ValueAnimator, you can receive an update at each frame, giving you a chance to update your object(s).

Here are two static factory methods that you can use to construct a ValueAnimator.

public static ValueAnimator ofFloat(float... values)

public static ValueAnimator ofInt(int... values)

Which method you should use depends on whether you want to receive an int or a float in each frame.

Once you create a ValueAnimator, you should create an implementation of AnimationUpdateListener, write your animation code under its onAnimationUpdate method, and register the listener with the ValueAnimator. Here is an example.

valueAnimator.addUpdateListener(new

ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

Float value = (Float) animation.getAnimatedValue();

// use value to set a property or multiple properties

// Example: view.setRotationX(value);

}

});

Finally, call the ValueAnimator’s setDuration method to set a duration and its start method to start the animation. If you do not call setDuration, the default method (300ms) will be used.

More on using ValueAnimator is given in the example below.

ObjectAnimator

The ObjectAnimator class offers the easiest way to animate an object, most probably a View, by continually updating one of its properties. To create an animation, create an ObjectAnimator using one of its factory methods, passing a target object, a property name, and the start and end values for the property. In recognition of the fact that a property can have an int value, a float value, or another type of value, ObjectAnimator provides three static methods: ofInt, ofFloat, and ofObject. Here are their signatures.

public static ObjectAnimator ofInt(java.lang.Object target,

java.lang.String propertyName, int... values)

public static ObjectAnimator ofFloat(java.lang.Object target,

java.lang.String propertyName, float... values)

public static ObjectAnimator ofObject(java.lang.Object target,

java.lang.String propertyName, java.lang.Object... values)

You can pass one or two arguments to the values argument. If you pass two arguments, the first will be used as the start value and the second the end value. If you pass one argument, the value will be used as the end value and the current value of the property will be used as the start value.

Once you have an ObjectAnimator, call the setDuration method on the ObjectAnimator to set the duration and the start method to start it. Here is an example of animating the rotation property of a View.

ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view,

"rotationY", 0F, 720.0F); // rotate 720 degrees.

objectAnimator.setDuration(2000); // 2000 milliseconds

objectAnimator.start();

Running the animation will cause the view to make two full circles within two seconds.

As you can see, you just need two or three lines of code to create a property animation using ObjectAnimator. You will learn more about ObjectAnimator in the example below.

AnimatorSet

An AnimatorSet is useful if you want to play a set of animations in a certain order. A direct subclass of Animator, the AnimatorSet class allows you to play multiple animations together or one after another. Once you’re finished deciding how your animations should be called, call the startmethod on the AnimatorSet to start it.

The playTogether method arranges the supplied animations to play together. There are two overrides for this method.

public void playTogether(java.util.Collection<Animator> items)

public void playTogether(Animator... items)

The playSequentially method arranges the supplied animations to play sequentially. It too has two overrides.

public void playSequentially(Animator... items)

public void playSequentially(java.util.List<Animator> items)

An Animation Project

The AnimationDemo project uses the ValueAnimator, ObjectAnimator, and AnimatorSet to animate an ImageView. It provides three buttons to play different animations.

The manifest for the application is given in Listing 15.1.

Listing 15.1: The manifest for AnimationDemo

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

package="com.example.animationdemo"

android:versionCode="1"

android:versionName="1.0" >

<uses-sdk

android:minSdkVersion="11"

android:targetSdkVersion="18" />

<application

android:allowBackup="true"

android:icon="@drawable/ic_launcher"

android:label="@string/app_name"

android:theme="@style/AppTheme" >

<activity

android:name="com.example.animationdemo.MainActivity"

android:label="@string/app_name" >

<intent-filter>

<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />

</intent-filter>

</activity>

</application>

</manifest>

Note that the minimum SDK level is 11 (Honeycomb).

The application has one activity, whose layout is printed in Listing 15.2

Listing 15.2: The activity_main.xml file

<LinearLayout

xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:paddingBottom="@dimen/activity_vertical_margin"

android:paddingLeft="@dimen/activity_horizontal_margin"

android:paddingRight="@dimen/activity_horizontal_margin"

android:paddingTop="@dimen/activity_vertical_margin"

android:orientation="vertical"

tools:context=".MainActivity" >

<LinearLayout

android:layout_width="match_parent"

android:layout_height="wrap_content">

<Button

android:id="@+id/button1"

android:text="@string/button_animate1"

android:textColor="#ff4433"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:onClick="animate1"/>

<Button

android:id="@+id/button2"

android:text="@string/button_animate2"

android:textColor="#33ff33"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:onClick="animate2"/>

<Button

android:id="@+id/button3"

android:text="@string/button_animate3"

android:textColor="#3398ff"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:onClick="animate3"/>

</LinearLayout>

<ImageView

android:id="@+id/imageView1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_gravity="top|center"

android:src="@drawable/photo1" />

</LinearLayout>

The layout defines an ImageView and three Buttons.

Finally, Listing 15.3 shows the MainActivity class for the application. There are three event-processing methods (animate1, animate2, and animate3) that each uses a different animation method.

Listing 15.3: The MainActivity class

package com.example.animationdemo;

import android.animation.AnimatorSet;

import android.animation.ObjectAnimator;

import android.animation.ValueAnimator;

import android.app.Activity;

import android.os.Bundle;

import android.view.Menu;

import android.view.View;

public class MainActivity extends Activity {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

}

@Override

public boolean onCreateOptionsMenu(Menu menu) {

getMenuInflater().inflate(R.menu.menu_main, menu);

return true;

}

public void animate1(View source) {

View view = findViewById(R.id.imageView1);

ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(

view, "rotationY", 0F, 720.0F);

objectAnimator.setDuration(2000);

objectAnimator.start();

}

public void animate2(View source) {

final View view = findViewById(R.id.imageView1);

ValueAnimator valueAnimator = ValueAnimator.ofFloat(0F,

7200F);

valueAnimator.setDuration(15000);

valueAnimator.addUpdateListener(new

ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

Float value = (Float) animation.getAnimatedValue();

view.setRotationX(value);

if (value < 3600) {

view.setTranslationX(value/20);

view.setTranslationY(value/20);

} else {

view.setTranslationX((7200-value)/20);

view.setTranslationY((7200-value)/20);

}

}

});

valueAnimator.start();

}

public void animate3(View source) {

View view = findViewById(R.id.imageView1);

ObjectAnimator objectAnimator1 =

ObjectAnimator.ofFloat(view, "translationY", 0F,

300.0F);

ObjectAnimator objectAnimator2 =

ObjectAnimator.ofFloat(view, "translationX", 0F,

300.0F);

objectAnimator1.setDuration(2000);

objectAnimator2.setDuration(2000);

AnimatorSet animatorSet = new AnimatorSet();

animatorSet.playTogether(objectAnimator1, objectAnimator2);

ObjectAnimator objectAnimator3 =

ObjectAnimator.ofFloat(view, "rotation", 0F,

1440F);

objectAnimator3.setDuration(4000);

animatorSet.play(objectAnimator3).after(objectAnimator2);

animatorSet.start();

}

}

Run the application and click the buttons to play the animations. Figure 15.1 shows the application.

image

Figure 15.1: Animation demo

Summary

In this chapter you learned about the new Animation API in Android, the Property Animation system. In particular, you learned about the android.animation.Animator class and its subclasses, ValueAnimator and ObjectAnimator. You also learned to use the AnimatorSet class to perform multiple animations.