Tuesday, May 20, 2014

Android SDK: Creating a Simple Property Animation

With Android you can include various types of animation in your apps. In this tutorial we will create a basic property animation using Android's Object Animator and Value Animator classes. The result will be simple but the techniques involved will apply in more complex animated effects. We will create an animation in which a steering wheel turns and the background scene moves accordingly.

With property animation, you have a few more options than with View animation, for example you can animate UI items other than Views and can animate more properties. Property animation can also have more consistent results in some cases, as unlike View animation, it alters the UI objects themselves, rather than just drawing them in particular ways. The downside to these advantages is that property animation is a little more complex - but it's still accessible for beginners.



Step 1: Start an Android Project


Start or open an Android project in Eclipse. You will need a blank Activity and a layout for it. You will also need to choose a minimum SDK of 11 in order to use the methods in this tutorial, so make sure your project Manifest indicates an appropriate level as in the following excerpt:

<uses-sdk
    android:minSdkVersion="11"
    android:targetSdkVersion="16"
/>

In the tutorial and source code, the app is named "PropertyAnimatedApp", the Activity is "PropertyAnimatedActivity" and the layout is "activity_property_animated.xml". You can choose your own names as long as you make changes to the below code where necessary.
 

Step 2: Add Images to the Project


We will be creating a few drawable files in XML for the animation, but will also be using a couple of PNG images. We will use the cloud and steering wheel images below within Image Views in the app layout. Download them from the copies displayed here or copy them from the source folder download. Make sure you copy them into each drawables folder in your app - you may wish to make adjustments to any of the drawable files we use if you plan on targeting particular screen sizes

 

Step 3: Create the Drawables


Now let's define the XML drawables for the remaining animation elements. In your application drawables folder(s), create the first new file by selecting the folder and choosing "File", "New", "File". Enter "sun.xml" as the file name. In the new file, enter the following code to define a sun shape:

    android:dither="true"
    android:shape="oval" >
    <gradient
        android:endColor="#ffff6600"
        android:gradientRadius="150"
        android:startColor="#ffffcc00"
        android:type="radial"
        android:useLevel="false" />
    <size
        android:height="100dp"
        android:width="100dp" />
</shape>

The drawable is an oval shape, with a radial gradient fill and specified size. When you finish entering code for each of the drawables files, save them and copy them into each drawables folder your app is using.

Create another new file in your app's drawables resources, this time naming it "ground.xml". Enter the following shape drawable:

    android:dither="true"
    android:shape="rectangle" >
    <solid android:color="#339933" />
</shape>

The ground will be represented by a green rectangle.

Create another drawables file, naming it "window.xml" and entering the following shape

    android:shape="rectangle" >
    <solid android:color="#00000000" />
    <stroke
        android:width="40dp"
        android:color="#cccccc" />
</shape>

This shape will represent a window frame around the edge of the screen, with a transparent fill so that only the stroke appears.

You can see each of the shapes as they will appear at the start of the animation below:

 

Step 4: Design the Layout


Now we can include our drawables in the layout. We will be using Image Views, with which we need to supply a content description String describing the image in each case. In preparation for this, open your app's "res/values/strings.xml" file and add the following values:

<string name="wheel">Steering Wheel</string>
<string name="ground">The Ground</string>
<string name="window">Window Frame</string>
<string name="sun">The Sun</string>
<string name="cloud">A Cloud</string>

We need a String for each of the images/drawables we will be using.

Now open your layout file. Replace the contents with the following Relative Layout:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/car_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#66ccff"
    tools:context=".PropertyAnimatedActivity" >
</RelativeLayout>

Alter the context attribute if your Activity class has a different name. Notice that we apply a background color to the layout - we will be animating this later, which is why we also include an ID attribute for referring to the layout in Java.

First inside the layout, add an Image View to display the sun shape we created:

<ImageView
    android:id="@+id/sun"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:contentDescription="@string/sun"
    android:paddingLeft="100dp"
    android:paddingTop="45dp"
    android:src="@drawable/sun" />

We include an ID attribute so that we can refer to the View when animating it. We also refer to one of the content description Strings we created and list the name of the drawable file as source src attribute. We also position the View within the layout.

Next add two more Image Views for the clouds:

<ImageView
    android:id="@+id/cloud1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:contentDescription="@string/cloud"
    android:paddingLeft="170dp"
    android:paddingTop="70dp"
    android:src="@drawable/cloud" />
<ImageView
    android:id="@+id/cloud2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:contentDescription="@string/cloud"
    android:paddingLeft="200dp"
    android:paddingTop="90dp"
    android:src="@drawable/cloud" />

These two are identical apart from the the positioning and ID attributes.

Next add the ground:

<ImageView
    android:id="@+id/ground"
    android:layout_width="fill_parent"
    android:layout_height="200dp"
    android:layout_alignParentBottom="true"
    android:contentDescription="@string/ground"
    android:padding="40dp"
    android:src="@drawable/ground" />

The ground is aligned to the bottom of the parent View. Notice that we also include padding on the bottom - this is to accommodate the window frame we will add next:

<ImageView
    android:id="@+id/window"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:contentDescription="@string/window"
    android:src="@drawable/window" />

The window shape uses a 40dp wide stroke, which is why we added 40dp of padding on the ground shape.

Each Image View added will be displayed on top of previous items in terms of the z-index so we add the steering wheel last:

<ImageView
    android:id="@+id/wheel"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_centerHorizontal="true"
    android:contentDescription="@string/wheel"
    android:padding="3dp"
    android:src="@drawable/steering_wheel" />

The layout will initially appear as follows:

 

Step 5: Define the Wheel Turning Animation


Let's get stuck into some animation now. In your app's "res" folder, create a new sub-folder by selecting "res" and choosing "File", "New", "Folder". Enter "animator" as the folder name. We will be adding two XML files to this folder, defining the wheel turning and sun moving animations. Start by creating a new file in "animator" and naming it "wheel_spin.xml".

Begin by adding a set element:

    android:interpolator="@android:anim/accelerate_decelerate_interpolator"
    android:ordering="sequentially" >
</set>

Inside the set we will define the details of the animation. In the opening set tag we specify an interpolator, in this case the accelerate decelarate interpolator so that the animation will speed up at the start and slow down at the end. We also specify ordering, which will not actually have an effect in this case as we are only going to define one animator within the set. If you have more than one, you can use this attribute to carry out the animations at the same time or sequentially.

Inside the set, include an animator to make the wheel turn:

<objectAnimator
    android:duration="3000"
        android:propertyName="rotation"
        android:repeatCount="infinite"
        android:repeatMode="reverse"
        android:valueTo="180"
        android:valueType="floatType" />

This is an Object Animator, which first defines a duration and property to animate over this period. The valueTo attribute indicates 180 degrees, which is how much the wheel will turn over the duration. When the animation completes, we set it to reverse and then repeat continuously.
 

Step 6: Apply the Wheel Turning Animation


Now let's turn to the Activity class. First add the following import statements at the top:
import android.animation.AnimatorInflater;
import android.animation.AnimatorSet;
import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.graphics.Color;
import android.view.Menu;
import android.widget.ImageView;

Inside the onCreate method, after the existing code, first get a reference to the wheel shape using the ID we gave its Image View:
ImageView wheel = (ImageView)findViewById(R.id.wheel);

Now create an Animator Set to load the animation we defined:
AnimatorSet wheelSet = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.wheel_spin);

Now set the View item as target for the animation:
wheelSet.setTarget(wheel);

Start the animation:
wheelSet.start();

You can run the app if you wish at this stage to see the wheel turning back and forth. The remaining animations will add to the effect, creating the impression that we are moving according to the steering, with the world outside the window moving back and forth at the same time.

Step 7: Define the Sun Moving Animation


Let's make the sun move to create the impression that we are moving as a result of the steering. Create a new file in your "animator" folder, this time named "sun_swing.xml". Enter the following code:

    android:interpolator="@android:anim/accelerate_decelerate_interpolator"
    android:ordering="sequentially" >
    <objectAnimator
        android:duration="3000"
        android:propertyName="x"
        android:repeatCount="infinite"
        android:repeatMode="reverse"
        android:valueTo="-400"
        android:valueType="floatType" />
</set>

This time the Object Animator animates the x property, moving the object to the left, as the steering wheel turns us to the right. The duration and repeat properties are the same as the wheel turn animation, as this effect is intended to coincide with it.

Step 8: Apply the Sun Moving Animation


Back in the Activity class onCreate method, apply this new animation to the sun View using the same technique as before:

//get the sun view
ImageView sun = (ImageView)findViewById(R.id.sun);
//load the sun movement animation
AnimatorSet sunSet = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.sun_swing);
//set the view as target
sunSet.setTarget(sun);
//start the animation
sunSet.start();

Run the app again if you wish to see the sun appearing to move out of view and back.

Step 9: Implement a Sky Darkening Animation


So far we have implemented a couple of animations by defining animation resources. Let's now explore creating animations in Java from the Activity class. We will make the sky go slightly darker when the sun moves out of view. Still inside onCreate, instantiate a Value Animator:
ValueAnimator skyAnim = ObjectAnimator.ofInt
    (findViewById(R.id.car_layout), "backgroundColor",
    Color.rgb(0x66, 0xcc, 0xff), Color.rgb(0x00, 0x66, 0x99));

We create the Value Animator by calling the ofInt method of the Object Animator class, as we are dealing with integer values for the colors. We pass the ID of the layout element which has the background color applied to it, also specifying "backgroundColor" as the property we wish to animate. Finally, we specify colors to animate from and to, which are lighter and darker shades of blue.

Set the duration and repeat properties to match the existing animations:
skyAnim.setDuration(3000);
skyAnim.setRepeatCount(ValueAnimator.INFINITE);
skyAnim.setRepeatMode(ValueAnimator.REVERSE);

Now set an evaluator to instruct the animator how to evaluate the passed color values:
skyAnim.setEvaluator(new ArgbEvaluator());

Start the animation:
skyAnim.start();

You can run the app to see the effect.

No comments:

Post a Comment