The Android platform facilitates three different types of animation you can define in your application resources: property, tween and frame. In this tutorial, we will create a simple tween animation using shape drawables displayed within Image Views. The end result will be an animation in which the sun rises, increasing in opacity and expanding as the tween elapses. We will also include a simple clock animation indicating the passing of time.
Step 1: Open or Start an Android Project
You can either create a new app or add the animation to an existing app. You will need an Activity class plus a layout for it. In the demo code, the app is named "AnimatedApp" with "AnimatedActivity" as the main Activity class and "activity_animated" for the layout XML file. We will be editing the Activity Java and the layout XML as well as creating various additional resource files.
Step 2: Create the Sky Shape Drawable
We will add the visual elements starting from the back and working towards the front, so let's create a shape drawable for the sky first. In your application drawable folder(s), create a new file by selecting the folder, choosing "File", "New", "File" (or right-click, "New", "File") and entering "sky.xml" as the file name.
Inside your new drawables XML file, enter the following code to represent the sky:
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:dither="true" android:shape="rectangle" > <gradient android:angle="90" android:endColor="#ff000033" android:startColor="#ff0000ff" /> </shape>
We define a rectangle shape with a blue gradient running from bottom to top. Dithering is enabled for the shape so that the gradient does not appear with banding (although sometimes it still will on the emulator).
Tip: Each time you create and complete a shape drawable file, remember to copy it into all drawables folders you plan on using for your app, amending the dimensions if you wish to tailor the shape to different device screen densities.
Step 3: Create the Sun Shape Drawable
Next create another drawable file, this time naming it "sun.xml". Inside it, define the sun shape as follows:
<shape xmlns:android="http://schemas.android.com/apk/res/android" 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="150dp" android:width="150dp" /> </shape>
This time, the shape is an oval, again with dithering. The fill is a radial gradient running from a deeper yellow to a lighter one. In this case we define an explicit size, whereas with the sky rectangle we are just going to let the shape fill the available space when we add it to the layout.
Step 4: Create the Grass Shape Drawable
Create another drawables file, this time named "grass.xml". Enter the following code to represent the grass:
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:dither="true" android:shape="rectangle" > <gradient android:angle="90" android:endColor="#ff003300" android:startColor="#ff009900" /> </shape>
This is another rectangle, this time with a vertical green gradient. We will define its dimensions and position when we add it to the layout file.
Step 5: Include the Drawables in the Layout
Now we can include our shapes in the Activity layout. We will be using Image Views, which require the Content Description attribute - a string value describing the image content. Before we start with the layout, open your app's "res/values/strings.xml" file and add the following:
<string name="sun">Sun</string> <string name="grass">Grass</string> <string name="sky">Sky</string> <string name="clock">Clock</string> <string name="hour">Hour Hand</string>
This includes values for the three shapes we have already defined plus two we will use later.
Now open your layout XML file. Replace any existing content with the following Relative Layout outline:
<RelativeLayout 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" tools:context=".AnimatedActivity" > </RelativeLayout>
Alter the context attribute if you are using a different Activity class name. Inside this layout, add an Image View for the sky shape:
<ImageView android:id="@+id/sky" android:layout_width="fill_parent" android:layout_height="fill_parent" android:contentDescription="@string/sky" android:src="@drawable/sky" />
We use an ID so that we can refer to the View in Java and apply the animation to it. The shape will fill the available screen space using the drawable we defined as its source src attribute.
Next add the sun shape, as we want it to appear in front of the sky but behind the grass:
<ImageView android:id="@+id/sun" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:contentDescription="@string/sun" android:scaleType="fitCenter" android:src="@drawable/sun" />
This time we wrap the content because we have defined the size explicitly in the shape drawable. Using a scale type allows us to instruct Android to fit the shape into the available screen size if it is too big. We center the sun shape horizontally within the layout.
Now add the grass:
<ImageView android:id="@+id/grass" android:layout_width="fill_parent" android:layout_height="150dp" android:layout_alignParentBottom="true" android:contentDescription="@string/grass" android:src="@drawable/grass" />
The grass shape will fill this View, which is defined to be a portion of the screen 150dp in height and aligned to the bottom of its container.
This is the layout initial appearance. We will be adding a couple more elements and altering the initial position of the sun.
This is what the Activity will look like when the animation begins on an actual device - we will add the clock later and the start position for the sun (at the bottom, behind the grass) will be determined as part of the animation code:
Step 6: Define the Sun Rise Animation
Now we can define the animation via which the sun shape will rise up the Activity screen. Create a new folder in your application's resources directory by selecting "res" and choosing "File", "New", "Folder" (or right-clicking and choosing "New", "Folder"). Name the folder "anim" - this is where our animation definitions will be stored.
Create a new file in the "anim" folder and name it "sun_rise.xml". In the new file, enter the following outline:
<set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="false" android:duration="5000" android:fillAfter="true" android:interpolator="@android:anim/accelerate_decelerate_interpolator" > </set>
We will specify the animation details inside the set element. Notice that the opening tag indicates the duration of the animation. We specify fillAfter so that the animation does not jump back to the beginning but rather retains its appearance at the end. We indicate the accelerate decelerate interpolator, which means that the animation will ease in and out, speeding up in the middle.
Inside the animation set, we can define the changes we want to take place. Let's make the sun expand in size as it rises - add the following scale element to resize the shape:
<scale android:fromXScale="1.0" android:toXScale="1.5" android:fromYScale="1.0" android:toYScale="1.5" android:pivotX="50%" android:pivotY="50%" />
The shape will begin at its normal size and end at 1.5 times that on both axes. The central point will remain the same, as we apply it as a pivot point for the scale.
Next add a translate element to move the sun up the screen:
<translate android:fromYDelta="80%p" android:toYDelta="10%p" />
The translate is purely vertical, so we only define the Y start and end points. We define the translation points relative to the parent element using the "p" suffix. The sun will start 80% along its parent element's Y axis and end 10% along it, moving it upwards as the animation elapses.
Let's also increase the opacity of the sun as it rises by adding an alpha element:
<alpha android:fromAlpha="0.3" android:toAlpha="1.0" />
The sun will start mostly transparent and end at full opacity.
Here is how the animation will appear mid-way:
Step 7: Apply the Animation
Now open your Java Activity class. First add the following import statements:
import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.widget.ImageView;
Inside your onCreate method, after the existing code, retrieve a reference to the sun Image View:
//get the sun View ImageView sun = (ImageView) findViewById(R.id.sun);
Now load the sunrise animation you defined:
//get the sunrise animation Animation sunRise = AnimationUtils.loadAnimation(this, R.anim.sun_rise);
We refer to the animation using its resource identifier. Now begin the animation, applying it to the sun View:
//apply the animation to the View sun.startAnimation(sunRise);
Run your app to see the sun rise, becoming brighter and expanding in size.
Here is the animation a little further along (including the clock which we will add next):
Step 8: Add a Clock Animation
To reinforce what we've learned, let's go through the process again to add a simple clock animation to the app. Start by creating a new drawable file called "clock.xml". This time we will use a Layer List to include more than one shape:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" > </layer-list>
Inside the Layer List add the first item, which is a circle shape:
<item> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:dither="true" android:shape="oval" > <gradient android:endColor="#ffffffff" android:gradientRadius="100" android:startColor="#66ffffff" android:type="radial" android:useLevel="false" /> <size android:height="100dp" android:width="100dp" /> <stroke android:width="2dp" android:color="#99000000" /> </shape> </item>
The shape is an oval, with a radial gradient, explicit size and stroke. Next, still inside the Layer List, add a clock hand shape:
<item android:bottom="44dp" android:left="48dp" android:right="48dp" android:top="5dp"> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <solid android:color="#99000000" /> </shape> </item>
This time we define the shape as a rectangle, with its properties relative to the circle shape it will appear on top of. We use the dimensions of the circle shape to make the rectangle appear like a minute hand on a circular clock face.
Now create a new file in your "anim" folder, naming it "clock_turn.xml". Define the animation inside it:
<set xmlns:android="http://schemas.android.com/apk/res/android" android:duration="5000" android:fillAfter="true" android:interpolator="@android:anim/linear_interpolator" android:shareInterpolator="false" > <rotate android:fromDegrees="0" android:pivotX="50%" android:pivotY="50%" android:toDegrees="720" /> </set>
This animation will elapse over the same period as the sun rise animation, as we give it the same duration. This time the interpolator is linear, so that the change will be applied at a constant rate throughout. The animation this time is a rotation, starting at the shape's initial position and rotating in two full circles (720 degrees). The circle center point will remain the same due to the pivot attributes. Although the entire circle shape will rotate, it will appear to the user as though the hand is turning around the clock face.
Add the clock to your layout XML file after the existing Image Views:
<ImageView android:id="@+id/clock" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:contentDescription="@string/clock" android:padding="10dp" android:src="@drawable/clock" />
It will appear in the bottom-right corner.
In your Activity class, after the existing sunrise animation code, get a reference to the clock:
//get the clock View ImageView clock = (ImageView) findViewById(R.id.clock);
Next load the animation:
//get the clock turn animation Animation clockTurn = AnimationUtils.loadAnimation(this, R.anim.clock_turn);
Now apply it to the clock shape:
//apply the animation to the View clock.startAnimation(clockTurn);
You can run your app again to see it in action.
Let's add an hour hand to the clock as well, so that the user can see the time advance two hours to match the two rotations of the minute hand. Create another drawable named "hour_hand.xml" and use the previous clock drawable as a template:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" > <item> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:dither="true" android:shape="oval" > <solid android:color="#00000000" /> <size android:height="100dp" android:width="100dp" /> </shape> </item> <item android:bottom="44dp" android:left="48dp" android:right="48dp" android:top="15dp"> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <solid android:color="#99000000" /> </shape> </item> </layer-list>
The only differences between this and the previous shape are the circle, which has a solid transparent fill in this case, and the hand rectangle, which is shorter. We don't bother with the stroke for the circle this time as it won't be visible anyway. By using the original clock shape as a guide, we can be sure this hand will rotate directly on top of the existing one.
Add the new shape to the layout XML after the existing items so that it appears on top:
<ImageView android:id="@+id/hour" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:contentDescription="@string/hour" android:padding="10dp" android:src="@drawable/hour_hand" />
It sits in exactly the same position as the previous shape.
Now create a new animation resource in your "anim" folder, naming it "hour_turn.xml". Define the animation again using the previous one as a guide:
<set xmlns:android="http://schemas.android.com/apk/res/android" android:duration="5000" android:fillAfter="true" android:interpolator="@android:anim/linear_interpolator" android:shareInterpolator="false" > <rotate android:fromDegrees="180" android:pivotX="50%" android:pivotY="50%" android:toDegrees="240" /> </set>
This time the shape will begin already rotated to 180 degrees, so that it will appear to be 6 o'clock. Over the same duration as the other animations it will move 60 degrees, so that at the end it will appear to be 8 o'clock, reflecting the two complete 360 degree rotations of the minute hand.
Open your Java Activity and apply the new animation:
//get the hour hand View ImageView hour = (ImageView) findViewById(R.id.hour); //get the hour turn animation Animation hourTurn = AnimationUtils.loadAnimation(this, R.anim.hour_turn); //apply the animation to the View hour.startAnimation(hourTurn);
Here is the animation at the end-point:
Conclusion
That's our simple tween animation complete! We have experimented with the set of elements you can use within a tween animation on a View element: translate, alpha, scale and rotate. You can alternatively use property animation to alter particular properties of an item over time, such as its color, or frame animation, in which you display an image sequence. The animation elements we used above have lots of additional attributes you can try, so experiment with your apps to see what's possible.
Comments