Chapter     8

An Introduction to Graphics Resources in Android

This chapter will serve as an introduction to how to best integrate and optimize graphical elements within your Android apps. These include static graphics such as bitmap images, as well as motion graphics, such as tween animation (transform-based or procedural animation), bitmap animation (frame-based or flipbook animation) as well as image transitions (crossfades, or blended image fades from one image into another image).

You will learn how to best use imaging techniques available to your application’s View objects that make up your UI, and how to support all four levels of Android screens (QVGA, HVGA, WVGA, and WSVGA) via custom resource assets.

Note  Because VGA is 640 × 480 pixels, quarter VGA (QVGA) is 320 × 240 pixels, or one-quarter of a VGA screen or LDPI; half VGA (HVGA) is 480 × 320, or one-half of a VGA screen (MDPI);  wide VGA (WVGA) is 800 × 480, or a widescreen version of a VGA screen (HDPI), wide SVGA (WSVGA) is 1,024 × 600; and the latest Android devices on the market are now supporting HD resolution, which is 1,280 × 720 and these would currently be termed XHDPI. Android 4.2 added the TVDPI specification, which supports GoogleTV iTV sets running 1920 x 1080 and Mega-Tablets running 1920 x 1200 resolutions.

We’ll cover the use of graphics objects in both the areas of user interface (UI) design (custom buttons, for instance) and user experience (UX) design (the content itself, say music videos or an interactive children’s storybook). If the graphic is used to control the operation of the app, it is classified as UI design, if the graphic is used as eye-candy, or is part of the content (the storyline for instance), it is classified as UX design. Both are vitally important to the success of your application.

We’ll look at two primary graphics related packages: the android.graphics.drawable package(I knew there was a reason that resource folder was called drawable) and the android.view.animation package. These are collections of useful classes for maximizing bitmap imagery and for working with images that support the fourth dimension (time) via motion, commonly called animation.

In a later chapter, once we know how to control events (which connect our UI elements to functions such as video playback), we’ll take a look at digital video. Using the VideoView class makes playing digital video a snap. Android 4.0 and later added one of the most impressive video codecs available today to Android. VP8 was acquired by Google from ON2 who developed it. It was originally called VP8 and is sometimes called WebM, as it was released for HTML5 by Google, who generously released this technology into open source. There is also a technology (supported in Android 4.0 and later) called WebP, which is the static image version of WebM. Both WebM and WebP use an advanced compression technology to get better quality with a smaller data footprint (better file compression, or a smaller file size). If you are developing for Android 4.x exclusively, you can use WebP instead of PNG24 and PNG32, otherwise, stick with PNG24 and it’s slightly larger (25% larger than WebP on average) file size.

Introducing the Drawables

The central set of classes used to control the graphics-related content within your Android application is called the drawable package. This package handles classes and methods related to drawing the following types of visual assets onto the Android display screen:

  • Bitmaps : In a bitmap, a collection of pixels make up an image—it’s a map of image bits, if you will. This is the most commonly used drawable asset.
  • Shapes : Shapes are line drawings. They also are known as vectors, like the lines architects use in CAD drawings. Common vector formats are EPS, AI, or SVG.
  • Gradients : Gradients are smooth transitions from one color to another color. They can be shaped in a straight line or occupy a circular area.
  • Transitions : Shape transitions are smooth vector changes between one shape and another shape. This process is sometimes referred to as morphing or tweening.
  • Animation : Animation involves an image, shape, or object that moves in some way.
  • Image transitions: These are smooth cross-fades between one image and another image. They are usually used to smoothly transition from one image to another image.

In Android development, graphics-related items such as gradients, image transitions, animated transformations, and frame-based animation can all be termed drawables. With the exceptions of transformational (tween or procedural) animation, all of these center their resource assets in the /res/drawable folder. (And you thought tweens were 12-year-olds, right?)

The /res/drawable folder is also where you should put XML files that define things like frame-based image animations and crossfading image transitions (which we will look at throughout this chapter). So get used to seeing drawable everywhere you look because it will be one of the most used folders in your resources (/res) folder.

Implementing Images

The way that Android is set up to automatically implement your images via the project folder hierarchy is a bit hard to understand at first. But once you get used to it, you’ll find that it is actually amazingly simple to use graphic resources, as extensive asset reference coding is all but eliminated. You will see this in action in this chapter, as we will implement powerful graphics features using as few as five or six lines of Java programming logic.

I’m not sure what could be much simpler than this: put your imagery into the appropriate project/res/drawable folder, and then reference it by file name in your Java or XML code. Yes, all that you need to do is reference it in your XML and Java code, and you are finished, and with perfect results (assuming that your imagery is optimized correctly, which we are also teaching in this book).

In this chapter, we will look at which image formats to use, which techniques to implement, and which work processes to follow as much as (or more than) we will be dealing with XML attributes and Java code snippets (although these are fun to play with as well).

Core Drawable Subclasses

Android offers more than a dozen types of customized drawable objects. In this chapter, we’ll look at the following core subclasses of android.graphics.drawable:

  • BitmapDrawable object : Used to create, tile, stretch, and align bitmaps.
  • ColorDrawable object : Used to fill certain other objects with color.
  • GradientDrawable object : Used to create and draw custom gradients.
  • AnimationDrawable object : Used to create frame-based animations.
  • TransitionDrawable object : Used to create crossfade transitions.
  • LayerDrawable object : Used to create composited PNG32 bitmaps or WebP bitmaps via multiple image layers.

Note  If you want to review all of the drawable objects, look at the android.graphics.drawable package document on the Android Developers website (http://developer.android.com/reference/android/graphics/drawable/Drawable.html). You’ll find that there is a plethora of graphics power in Android’s 2D engine.

The most pervasive and often used type of drawable is the bitmap. A bitmapis an image composed of a collection of dots called pixels,where “pix” stands for “pictures” and “els” stands for “elements.” Yes, a bitmap is, quite literally, a map of bits. So, let’s get started with adding bitmaps to your Android apps.

Using Bitmap Images in Android

How do we best optimize our static (motionless or fixed-in-place) bitmap imagery for use within our Android applications? That’s what this section is all about. We have already worked with bitmap images in the previous chapters, in the context of our ImageButton and ImageView objects, so you already have a decent amount of experience with using truecolor 32-bit PNG (PNG32) files to obtain an excellent graphic result. Remember that a 32-bit PNG is a portable network graphic format with 8-bits of red, green, blue, and alpha (ARGB or RGBA) and that 4 × 8 = 32, thus: PNG32.

Besides the WebP format that is supported in Android 4.0 and later, Android supports three mainstream bitmap image file formats: PNG, JPEG, and GIF. We’ll talk about how Android truly feels about each one, so you can choose the right formats to meet your graphics-related design and user experience objectives.

PNG Images

The most powerful file format that Android supports, and the one that it recommends using over all others, is the portable network graphics, or PNG (pronounced “ping”) format. There are two primary types of PNG:

  • Indexed-color PNG8, which uses a limited 256-color (8-bits of color allows 256 color values) image palette, which is an index of up to 256 colors that an image uses to make up its pixel colors
  • Truecolor PNG32, which uses a 32-bit color image that includes a full 8-bit alpha channel (used for image compositing) and 8-bits each of red, green, and blue image channels, or PNG24 for a truecolor PNG image with no alpha channel included

PNG is known as a lossless image file format because it loses zero image data during the compression processing. This means that the image quality is always 100% maintained. If designers know what they are doing, they can get very high-quality graphics into a reasonably small data footprint by using either the indexed-color PNG8 or the truecolor PNG32 or PNG24 image file formats, depending upon how many colors are using in that image.

Indexed-color PNG8 files use approximately one-fourth of the amount of data (bits) that a truecolor 32-bit RGBA PNG32 image does. Remember the math we did in the previous chapter: 8 × 4 = 32. A smaller data footprint is achieved by using only 8 bits, or a 256-color “palette” of 256 of the most optimal (the most frequently used in the image) colors that are best suited to represent a particular image, but with much the same visual result as if 24-bits (16,777,216 colors) worth of color values were used. This is done primarily to save data file size, thereby decreasing the image’s data footprint (file size) considerably.

Each 8-bit “indexed” color image (PNG8 or GIF) will have its own custom index or palette of colors to use to represent the pixels in that image. More colors can be simulated in 8-bit images by “dithering,” which is a process where fine dot patterns are used between two different colors to simulate an intermediate color (similar to the concept of anti-aliasing that we discussed earlier in the book). This is done to minimize “color banding” in 8-bit images, and dithering is an option in the 8-bit image compression process that can be turned on or off as needed. Dithering adds a small amount of data overhead to the file size, or increases the data footprint slightly, within the resulting file, as more data (the resulting dot patterns) is added to the compressed file, but the visual results are usually well worth the few extra kilobytes.

Truecolor PNG32 images use a full 32 bits of data for each of the image pixels to represent the four image data channels that are found in most bitmap images: alpha channel, red channel, green channel, and blue channel (RGBA or ARGB). If an alpha channel is not used to define image transparency for compositing purposes, then the RGB PNG image would be called a 24-bit PNG24 image, as it uses 24-bits (3 × 8) of data, rather than 32-bits.

The alpha channel determines where the image is going to be transparent and is used for image compositing. As you learned in Chapter 7, compositing is the process of using more than one image in a series of layers to create a final image out of several component layers or parts. Image compositing is so important that Android even has a LayerDrawable, which you learned at the beginning of this chapter, and which you can research farther at: http://developer.android.com/reference/android/graphics/drawable/LayerDrawable.html if you are going to be doing a lot of compositing in your application. We already looked at using layers in GIMP earlier in the book, and this drawable class gives your Android applications this same capability.

Another benefit of image compositing is that in your programming code, you can access different image elements of a composited or layered image independently of other image elements because they are all on their own layer. For example, you might do this for more advanced game engine programming, where what seems to be one image to the game player is actually in fact a series of image layers that composite seamlessly together at run time, via code and clever GIMP or Photoshop compositing work. This allows your Java (and XML) code to grab onto individual image elements without having to use 3D (OpenGL ES) rendering, which is beyond the scope of an introductory book such as this but which we look at in Chapter 12 just so that you know about it.

It is important to note that at compile time, Android looks at your PNG32 (or PNG24) graphics, and if they use less than 256 colors within the image, Android automatically remaps them to be an indexed PNG8 image, just as you would want it to do to save space (app data footprint). This means that you don’t need to worry about analyzing your images to see if they should be in truecolor or indexed-color PNG format. You can simply do everything in truecolor, and if it can be optimized into indexed-color with no loss of data, Android will do that for you—making your data footprint three to four times smaller, depending on if you have used an alpha channel (PNG32 RGBA) or are using only the RGB image channels (PNG24 RGB).

If for some reason you don’t want your images optimized at compile time, you can put them into the project /res/raw folder, which is for data that is accessed directly from your Java code. A good example of this is video files that have been perfectly optimized for size and quality, and just need to be played. This concept will come up in a media player example in Chapter 11, so stay tuned, as we will be using the /raw folder soon enough, I just wanted to point it out here, as it relates to circumventing the mandatory PNG image optimization that Android has implemented into it’s compile-time processing.

JPEG and GIF Images

The next most desirable format to use is the JPEG image file type. This type does not have an alpha channel. It uses lossy compression, which means that it throws away some data to get a much better compression result, but at the expense of your image quality. JPEG stands for joint photographic experts group.

If you look closely at (zoom into, using GIMP) JPEG images, you will see a lot of artifacts, such as areas of strange color variations or what looks like dirt on the image (dirt that was not on the camera lens). JPEG is useful for much higher-resolution (print resolution) images, where artifacts are too small to be seen. So, it is not really as suitable for lower-resolution smartphone screens. JPEG is supported, but is not recommended for Android apps because Google wants their product to look as pristine as possible, and PNG or WebP formats are the sure-fire way to accomplish this.

Finally, we have GIF, the CompuServe graphic information format, a much older 8-bit file format. The use of this file format is discouraged because it has the poorest quality to file size ratio. Stay away from using GIFs for your Android apps if possible. Use PNG8 instead, as it has a superior image compression algorithm that results in a smaller data footprint (file size).

Creating Animation in Android

You’ve already learned how to implement static bitmap images in previous chapters via the activity_main.xml file in the /res/layout/ folder. So, let’s get right into the fun stuff with animation and add some motion to your Android app screen.

Frame-Based or Cel-Based 2D Animation

Traditional 2D animation involves moving quickly among a number of what originally in the cartoon industry were called cels, or hand-drawn images, creating the illusion of motion. To steal a more modern term from the movie industry, each image, which is a little bit different from the next, is called a frame. This term refers back to the original days of film, where actual film stock would be run through a projector, displaying 24 frames per second (known in the industry as fps).

In Android, frame-based animation is the easiest to implement via XML and gives us great results. You just need to define some basic XML animation attributes—what and where the frames are—in the correct place for Android to find them. Then you can control your animation via your Java code if you need to.

In our example, we are going to animate a solid gold 3D logo. It will circle around smoothly, casting a T-shaped shadow onto the ground. Let’s fire up a new project in Eclipse, and we’ll see how animation works in Android.

  1. If you still have the UI_Design project folder open from the previous chapter examples, right-click on that folder, and select Close Project. This closes the project folder in Eclipse (of course, it can be reopened later; as you can see, it’s still there).
  2. Select Eclipse File image New image Project and choose Android Application Project to open the New Android Application Project dialog sequence. Fill it out as follows (and shown in Figure 8-1).
    • Project name : Name this project GraphicDesign.
    • Application name: Let’s call this application GraphicDesign.
    • Package name : Name the package fourth.example.graphicdesign.
    • Build SDK target : Choose Android 4.1 SDK Level 16 (Jelly Bean).
    • Min required SDK version : Enter API Level 8, which matches with the recommended Android 2.2 compatibility build target setting.
    • Create custom launcher icon : Check this box.

    9781430247883_Fig08-01.jpg

    Figure 8-1 .  Creating our GraphicDesign Android 4.1 project

  3. Now we need to define our animation’s frames in an XML file, which we’ll call logo_animation. Right-click your GraphicDesign folder and select New image File. At the bottom of the dialog, enter logo_animation.xml. In the GraphicDesign navigation pane in the middle of the dialog, expose your directory structure (via the arrows next to the folders), and select the /res/drawable folder, so that the parent folder field above shows GraphicDesign/res/drawable-xhdpi. This places our logo_animation XML file in the correct folder. Figure 8-2 shows the completed New File dialog as well as the drop-down menu sequence, together in a single screenshot.

    9781430247883_Fig08-02.jpg

    Figure 8-2 .  Creating our logo_animation.xml file in the GraphicDesign/res/drawable-xhdpi folder

    Caution  Because frame-based animation in Android uses bitmap images, you must place the XML file that references these bitmap images into the same folder the images occupy: the /res/drawable folder. Do not put frame animation images or XML specifications into the /res/anim folder. That folder is for transform animation (covered in the next section of this chapter). This is an important difference in how frame-based animations and transform-based or tween animations are set up and created in Android. This is also a very common mistake, as one would assume that all animation-related XML would logically go into the /res/anim/ folder, but this is not in fact the case. Bitmap (frame) animation goes into the /res/drawable/ folders alongside the image assets that it uses, and procedural (vector) animation goes into /res/anim. Memorize this now to avoid hours of frustrating debugging later on!

  4. Next, click the logo_animation.xml tab in Eclipse, and type in the following XML markup to define our frame-based animation for Android (Figure 8-3 shows the new file in Eclipse):
 
<animation-list xmlns:android="http://schemas.android.com/apk/res/android "
 android:oneshot="false">
    <item android:drawable="@drawable/logoanim0" android:duration="200" />
    <item android:drawable="@drawable/logoanim1" android:duration="200" />
    <item android:drawable="@drawable/logoanim2" android:duration="200" />
    <item android:drawable="@drawable/logoanim3" android:duration="200" />
    <item android:drawable="@drawable/logoanim4" android:duration="200" />
    <item android:drawable="@drawable/logoanim5" android:duration="200" />
    <item android:drawable="@drawable/logoanim6" android:duration="200" />
    <item android:drawable="@drawable/logoanim7" android:duration="200" />
    <item android:drawable="@drawable/logoanim8" android:duration="200" />
    <item android:drawable="@drawable/logoanim9" android:duration="200" />
</animation-list>

9781430247883_Fig08-03.jpg

Figure 8-3 .  Creating the XML mark-up for the logo_animation.xml file

This is pretty straightforward XML tag markup logic here. We add an animation-list tag to hold our frame-based animation image (item) listings. This tag has its android:oneshot attribute set to false, which will allow our seamless animation to loop continuously. Setting oneshot equal to true will stop the animation after one full iteration through the ten files. We’ll try both settings later, so that you can get used to using this important parameter.

Inside of the animation-list tag, we have ten nested item tags (nested because the animation-list closing tag comes after these ten item tags). These specify the location of each image in our /res/drawable-xhdpi folder, where each image is a frame in the animation.

Using each item tag entry, we specify the name and location of each of our ten animation frames logoanim0 through logoanim9, as well as the duration of the frame display time in milliseconds (ms). In this case, we start off using 200 ms, or one-fifth of a second, for each frame, so that the entire animation plays over 2 seconds, and at 5 fps, just barely fast enough to fake movement. We can adjust frame times later, to fine-tune the visual result and to make the animation loop more smoothly and more rapidly.

We need to put our animation frame images into the /res/drawable-xhdpi folder, so that the XML code can reference them successfully. As you know by now, in Android, everything needs to be in the correct place for things to work properly (or at all, for that matter).

  1. Copy the ten animation frames into the /res/drawable-xhdpi folder from the code download.
  2. Right-click the GraphicDesign folder in the Package Explorer and select Refresh, so that the IDE can see the new animation frame image assets that you have added.
  3. If there are still errors on your XML editing pane, right-click your GraphicDesign folder and select Validate to clear these as well. Validate checks and validates your project and all of its code, so it looks one level deeper than Refresh, which just looks at folders to make sure that Eclipse sees all of your resource assets.

At this point, you should see a screen that looks similar to Figure 8-3.

Controlling Frame-Based Animation via Java

Now we are going to write our Java code to access and control our 2D animation. If the MainActivity.java tab is not already open, right-click the MainActivity.java file in the Package Explorer pane, and select Open, or simply select the file and then hit the F3 key.

Note  To right-click the MainActivity.java file, the /src folder and subfolders need to be showing in the expanded Package Explorer project-tree view, so click on those arrows to make your Java Source Code hierarchy visible.

Here is the code for our MainActivity.java file, which holds our MainActivity class from our fourth.example.graphicdesign package:

package fourth.example.graphicdesign;
 
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.ImageView;
import android.graphics.drawable.AnimationDrawable;
 
public class MainActivity extends Activity {
 
    AnimationDrawable logoAnimation;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        final ImageView logoAnimHolder = (ImageView) findViewById(R.id.imageView1);
        logoAnimHolder.setBackgroundResource(R.drawable.logo_animation);
        logoAnimHolder.post(new Runnable() {
        public void run() {
              logoAnimation = (AnimationDrawable) logoAnimHolder.getBackground();
              }
        } );
    }
    @Override
    public void onWindowFocusedChanged(boolean hasFocus) {
         logoAnimation.start();
    }
    @Override
    Public boolean onCreateOptionsMenu(Menu menu) {
         getMenuInflater().inflate(R.menu.activity_main, menu);
         return true;
    }
}

In Android Java code, AnimationDrawable is the class we need to use to implement our frame-based animation sequences. We import the android.graphics.drawable.AnimationDrawable class. Then we import the android.widget.ImageView class, which we will use as a view container to display the animation. We add the two new import statements to the ones that Android starts us out with (the first three).

Next, we add the object declaration for our AnimationDrawable object, which we are calling logoAnimation. This is as simple as writing the following:

AnimationDrawable logoAnimation;

Next, we create a final ImageView object called logoAnimHolder, which we assign to ImageView imageView1, which we will declare in the activity_main.xml file and access via the findViewById() method.

After that, we set the background resource for this newly created ImageView to our logo_animation XML file, which specifies our animation sequence and timing. This is the bridge between display (ImageView) and animation data definition (logo_animation.xml) that we set up via the .setBackgroundResource() method so that our animation will display through the background image setting for the ImageView.

If you are wondering why we are using the ImageView widget’s Background Image parameter rather than the Source Image, this leaves it open for us to have a source image in ourImageView that uses transparency (an alpha channel) to create cool effects on top of the animated background. This essentially gives us two layers in the ImageView UI Object, as we can set source and background images for any ImageView object, and both of these could be animated if we like. If you need to, you can get some more practice by changing this source code from using getBackground() and setBackgroundResource() to instead using setImageResource() and getImageResource().

To run the animation we use the .post() method on the logoAnimHolder ImageView to implement (post to the OS) a runnable() method that will contain our run() method that runs (cycles through the animation frames, in this case) our core animation drawable object logoAnimation that we declared at the top of our MainActivity Class.

Inside of the run() method, we define the logoAnimation object that we want to run() and which we declared in the very first line of code in our MainActivity class. The logoAnimation is an AnimationDrawable object that gets its data from the logoAnimHolder object via its getBackground() method, which grabs the ImageView background image. As you can see from the logoAnimHolder .setBackgroundResource() declaration a few lines earlier, that image has been obtained from the logo_animation.xml file, where we define our animation frame sequence.

Thus, to get our animation to play, we use a new method called post(). This method uses a new Runnable method to invoke a run() method that runs the getBackground() method that gets the animation frames from our logoAnimHolder ImageView object. This is the code that handles the real-time nature of getting the frames every 200 ms and putting them into the ImageView object background for display on the screen.

To finally get our animation to play on the screen when the app launches, we use a onWindowFocusChanged() method to initially detect when the window (app UI screen) has Focus, in this case, to detect when the app has started, or more precisely, when the onCreate() and run() methods have finished loading (preparing themselves for execution). If we don’t do this, then our app tries to run our animation before the screen is ready to accept it, and the gold logo does not animate.

Inside of the onWindowFocusChanged() method, we have our call to start() the logoAnimation object via, you guessed it, a logoAnimation.start(); line of code, instructing the logoAnimation object to start animating now that the app window has the focus and is ready to display animation!

Notice that we have not touched our standard (automatically generated) onCreate() method of our activity, we are still using our default activity_main.xml UI layout specification and our onCreateOptionsMenu() method of our activity is using our activity_main.xml UI menu specification, which in this app is not utilized. Figure 8-4 shows the four logical sections of code that we need to add to the default MainActivity class andonCreate() and onWindowFocusChanged() code:

  • Import the Android Java classes that we are leveraging in our code.
  • Create and name an AnimationDrawable object that is accessible to every code construct in our MainActivity class.
  • Create an ImageView object tied to our activity_main.xml screen layout, set the background image resource of that ImageView to reflect our logo_animation.xml attributes, and then have our logoAnimation AnimationDrawable object take that frame data from the ImageView via getBackground().
  • Run the animation with a run()method inside of an Android Runnable thread created by our logoAnimHolder.post() method.
  • Start the animation using logoAnimation.start() method inside of our onWindowFocusChanged() method used to detect app initialization completion.

9781430247883_Fig08-04.jpg

Figure 8-4 .  Creating the Java code that sets up and starts our XML defined frame-based animation

Finally, we need to remember put in place the ImageView named imageView1, which ties the ImageView in our Java code to the ImageView defined in our XML document (activity_main.xml) that defines our screen layout UI. To set-up our UI Layout activity_menu.xml markup in /res/layout/, we’re using a default RelativeLayout container with an ImageView called imageView1 inside of it to hold our frame animation.

Here is the code, which is also shown in Figure 8-5:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android "
    xmlns:tools="http://schemas.android.com/tools "
    android:id="@+id/relativelayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
 
    <ImageView
    android:id="@+id/imageView1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentTop="true"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="=24dp"
    android:contentDescription="@+string/content_desc" />
</RelativeLayout>

9781430247883_Fig08-05.jpg

Figure 8-5 .  Naming our ImageView UI element in the activity_main.xml file so it matches the imageView1 name used in our Java code

In this case, we have a RelativeLayout that contains an ImageView object named imageView1, the default name that Android assigns to the first ImageView object declared or created by the Graphical Layout Editor (just in case you used that work process to create your UI).

We set our ImageView to wrap_content (basically to conform the ImageView boundaries to the 240 × 180 pixel dimension of our animation’s imagery, and thus to “shrink-wrap” our animation sequence inside of our ImageView widget).

The next three parameters were automatically written for us based on our placement in the Graphical Layout Editor, and the final android:contentDescription parameter points to a short line of XML markup that we need to add to our /res/values/strings.xml file that reads (place here whatever content you want the physically impaired to hear):

<string name="content_desc">Frame Animation Example</string>

Running the Frame-Based Animation App in the Emulator

Now let’s see our animation in action. Right-click your GraphicDesign folder and choose Run As image Android Application. When the 4.1 emulator comes up with a white screen, watch the 3D gold logo animation playing on it—simply amazing. But a tad too slow as the animation is not smooth enough. You’ll fix that next with a little parameter “tweaking!”

Because a screenshot cannot display an animation, we’ll forego the screenshot of the 4.1 emulator here to save space. Now, here’s a simple exercise to try after you run this version. Make the following changes, and then save the modified logo_animation.xml file:

  1. Change the logo_animation time values from 200 to 100 for all of the image parameters. This will play the animation faster, with a 1 second duration, at 10fps or ten frames per second, yielding a smoother animation result.
  2. Change the animation-list tag’s android:oneshot attribute to true.

To run our nonlooping smoother animation version, right-click the GraphicDesign folder and select Run As image Android Application. Now when you launch the app in the 4.1 emulator, the animation will play one time and then stop. Note that by increasing the frame-rate that we obtained a much smoother visual appearance.

Next, let’s add a transformational animation directly underneath our frame-based animation.

Tween Animation in Android

Tween animation is used for shape-based animation, where shapes are animated from one state to another without specifying the intermediate states. In other words, you define the start and end positions of the shape, and Android fills in the gaps to make the animation work. This shape based animation is sometimes called “Vector Animation” whereas frame based animation would be called “Raster Animation.”

This contrasts with frame-based animation, which uses a sequence of cels, or bitmap images, as the flipbook animations of days gone by. So, frame animation does its work via pixels, while tween animation does its work via transforms that move, rotate, or scale a shape, image, or even text. Thus, tween animation is more powerful than frame-based animation. It can also be used in conjunction with frame-based animation to achieve even more spectacular results.

Tween animation in Android is completely different than frame animation. It is implemented with the set of classes found in the android.view.animation package. These classes represent the true power of tween animation in Android. They include things such as advanced motion interpolators, which define how animation transformations accelerate (or decelerate)  over time; and animation utilities, which are needed to rotate, scale (resize), translate (move), and fade (effect transparency) View objects over time.

“Wait a minute,” you must be musing, “does ‘View objects’ mean that I can apply all of this animation class power to, say, TextViews, for instance? Or even VideoViews?” Indeed it does. If you transform a TextView (rotate it, for instance), and it has a background image, that image is transformed correctly, right along with the text elements of the TextView and all of its settings.

Note  Here, the word transformation refers to the process of rotation (spinning something around a pivot point), scaling (resizing in x and y dimensions relative to a pivot point or reference point), and x or y movement, which is called translation in animation. Don’t get Translation and Transformation confused!

As you might imagine, tween animation definitions can get very complex. This is where the power of using XML to define complicated things, such as transformational animation constructs, becomes very apparent. Again, we thank Android for off-loading work like this from Java coding to XML constructs, so our designers can take care of it for the programmers.

In XML, the tween animation transforms are simply lists of nested tags; they are not usually set up via classes and methods. It is certainly far easier to fine-tune and refine these types of detailed animations via XML line-entry tweaks, rather than inside of the Java code, although you could probably do it that way if you wanted to, once you are an expert Java programmer.

The XML for tween animations goes in an entirely different directory (folder) than frame animation (which goes in /res/drawable). Transform animation XML definitions (files) go in the /res/anim folder.

Creating the text_animation.xml File

We will use a different XML file-creation method to create our transform animation XML file and its folder, so let’s get into that right now.

  1. Open the Eclipse File Menu at the top left of the IDE and select New image Other... image Android image Android XML File, as shown in Figure 8-6. Then click Next.

    9781430247883_Fig08-06.jpg

    Figure 8-6 .  Selecting to create a new XML file via the Eclipse File image New image Other menu selection route and dialog

  2. As you can see by the options in the New Android XML dialog, Android in Eclipse has a powerful XML file-creator utility that supports ten different genres of XML files via a drop-down menu, including animation. Fill out the dialog as follows (and as shown in Figure 8-7):
    • File : The first field we want to fill out is the name of the animation XML file, which is: text_animation.xml.
    • Which type of resource would you like to create? : Select Tween Animation as the XML file type, which automatically puts the XML file created into the /res/anim Folder.
    • Select the root element for the XML file : Make sure that set is selected as the root element for the file. (The root element is the outermost tag in an XML file and contains all of the other tags.) A <set> is used to group and nest transforms into a Set of Transforms to achieve more powerful and flexible results, as you will see in our transform XML mark-up.

      9781430247883_Fig08-07.jpg

      Figure 8-7 .  Filling out the New Android XML File dialog to specify the Tween Animation XML file

  3. Now click Finish. You will see the /res/anim folder appear in your project hierarchy tree in the Package Explorer pane, with the text_animation.xml file inside it.
  4. Now let’s add in our XML tags to define our scale and rotation transforms, as shown in Figure 8-8. (Click the Source tab at the bottom of the main window to open the XML code editing window if it does not appear automatically.)
<set xmlns:android="http://schemas.android.com/apk/res/android "
     android:shareInterpolator="false">
 
    <scale android:interpolator="@android:anim/accelerate_decelerate_interpolator"
          android:fromXScale="1.0"
          android:toXScale="1.4"
          android:fromYScale="1.0"
          android:toYScale="0.6"
          android:pivotX="50%"
          android:pivotY="50%"
          android:fillAfter="false"
          android:duration="700" />
 
    <set android:interpolator="@android:anim/decelerate_interpolator">
        <scale android:fromXScale="1.4"
                android:toXScale="0.0"
                android:fromYScale="0.6"
                android:toYScale="0.0"
                android:pivotX="50%"
                android:pivotY="50%"
                android:startOffset="700"
                android:duration="400"
                android:fillBefore="false" />
 
        <rotate android:fromDegrees="0"
                android:toDegrees="-45"
                android:toYScale="0.0"
                android:pivotX="50%"
                android:pivotY="50%"
                android:startOffset="700"
                android:duration="400" />
    </set>
</set>

9781430247883_Fig08-08.jpg

Figure 8-8 .  Coding our tween animation tags and their parameters in the text_animation.xml file

Notice that there are quite a few attributes for the tags that allow transformational animation over time. For instance, our scale tags allow us to specify to and from values for both the x and y dimensions, pivot points (where the scale emanates from, or from which location on the object the scale is to be performed), scale offsets for nonuniform scaling, time duration, and whether to fill before or after the transformation.

For rotation tags, we have rotation to and from degree specifications, as well as x and y pivot point settings. We also have both an offset for skewed rotations and a duration attribute that controls the speed of the rotational transformation. The pivot point defines the center point of the rotation, and an offset defines how to skew the rotation from that point, much like the old Spirograph sets that created cool, flower-like graphics.

Controlling Tween Animation via Java

Now that our TextView transform animation XML data is in place inside of our newly created /res/anim/text_animation.xml file, we can insert a half dozen lines of Java code into our MainActivity.java file, to implement the transform animation within our application, directly underneath our frame-based animation.

  1. As shown in Figure 8-9, the first thing we must do is to import the Android classes that are going to be used in the text animation transformation: android.widget.TextView and the android.view.animation classes called Animation and AnimationUtils.
    import android.widget.TextView;
    import android.view.animation.Animation;
    import android.view.animation.AnimationUtils;

    9781430247883_Fig08-09.jpg

    Figure 8-9 .  Setting up our text tween animation in our GraphicDesign project's Java code

  2. Then down in our onCreate() method, we specify the TextView object textAnim and the Animation object textAnimation.
    TextView textAnim = (TextView) findViewById(R.id.animText);
    Animation textAnimation = AnimationUtils.loadAnimation(this,               
                               R.anim.text_animation);
  3. We then call the startAnimation() method on the TextView object, specifying that we want to use the textAnimation Animation object.
    textAnim.startAnimation(textAnimation);
  4. Finally, we need to add a TextView object named animText to our RelativeLayout tag and UI container in our activity_main.xml file, as shown in Figure 8-10.

    9781430247883_Fig08-10.jpg

    Figure 8-10 .  Adding a TextView UI object to our activity_main.xml file with an ID of animText

  5. Now we can try out the tween animation. Right-click the GraphicDesign folder in the Package Explorer pane and select Run As image Android Application. It only runs once (it is not looped), so keep an eye on the emulator as it starts up!
  6. It runs pretty fast. Let’s add a zero on the time values in our text_animation.xml file, changing 400 to 4,000 and 700 to 7,000.
  7. Compile and run the app again. You’ll see that the animation runs ten times slower, so you can actually see what the transforms are doing to the text object. If you want it to run another order of magnitude (10×) slower still, simply add another zero as we did in Step 6 above.

Using Transitions

Transitions are preprogrammed custom special effects, like crossfades (also called dissolves) and things such as directional wipes, which we can code ourselves. By using these effects, especially in combination with each other, you can increase the perceived professionalism of your application.

You can (and should) use XML to set up such graphics transition transformations.

Android provides the TransitionDrawable class. Here, we will use it in conjunction with an XML file in the /res/drawables directory, just as we did in the frame-based animation example because transitions are designed to work with bitmap images just like frame-based animation.

So, let’s get started.

  1. Right-click the GraphicDesign folder and select New image File to create a standard text file for our XML in the /res/drawable-xhdpi folder (because we are working with bitmap images).

    Name the file image_transition.xml, found at the bottom of the New File dialog. We’ll forego the screen shot because you’ve seen it before. Open the GraphicDesign folder, then open the /res folder, then select the /drawable-xhdpi folder, where the new file will be created.

  2. Next, add the <transition> tag as follows. The <transition> tag has the usual xmlns reference (to make our file valid Android XML). Inside the tag, we specify two <item> tags referencing the images that we need to transition from and transition to. We are using the two images that we used in Chapter 7 here to show that the transitions will accommodate the alpha channel and more complicated masking of images, which is important for advanced animation design:
    <transition xmlns:android="http://schemas.android.com/apk/res/android ">
     
        <item android:drawable="@drawable/image1"/>
        <item android:drawable="@drawable/image2"/>
     
    </transition>
  3. Add these two images to the /res/drawable-xhdpi folder. Figure 8-11 shows what your screen should look like once you have added the two images, refreshed the IDE, and typed in your tags.

    9781430247883_Fig08-11.jpg

    Figure 8-11 .  Writing our XML markup to transition between two images in our image_transition.xml file

  4. Now we need to add an ImageView in our RelativeLayout to hold our image transition source imagery. Put the following in the activity_main.xml file underneath our animated TextView, as shown in Figure 8-12.
        <ImageView

           android:id="@+id/imageTrans"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_below="@+id/animText"
           android:layout_centerHorizontal="true"
           android:layout_marginTop="48dp"
           android:src="@drawable/image1"
           android:contentDescription="@+string/content_desc2" />

9781430247883_Fig08-12.jpg

Figure 8-12 .  Adding an ImageView UI object to our /res/layout/activity_main.xml file to hold our image transition

We are specifying the first image (the “from” image) of our transition as the source image to use in the ImageView object, and we are naming it imageTrans via the now familiar @+id/imageTrans notation. We are also using the now familiar RelativeLayout android:layout_ below parameter to place the imageTrans ImageView object underneath (below) the animText TextView object, and using the layout margin and centering parameters as we did with the other two objects declared in the activity_main.xml found in the /res/layout/ folder.

Finally, let’s not forget the sight impaired, and let’s add an android:contentDescription parameter, which should, via our /res/values/strings.xml file, reference the text “Image Animation Example.” Be sure to right-click and open the strings.xml file and copy and paste the content_desc string tag, and then change the name to be content_desc2 and value to be Image Animation Example because we are referencing this in our activity_main.xml file here.

Now we are ready to drop a few lines of Java code (a whopping five this time) into MainActivity.java to add the ability to do a fade transition from one image slowly into another.

First we need to add the import statement for the class library that we are going to use in the Image Transition example, namely the android.graphics.drawable.TransitionDrawable class:

import android.graphics.drawable.TransitionDrawable;

Here is the code to set up the TransitionDrawable implementation that we will use to create the trans object that is used to access the image_transition XML file in our /res/drawable-xhdpi folder:

TransitionDrawable trans = (TransitionDrawable)
  getResources().getDrawable(R.drawable.image_transition);

This is all on one line, as shown in Figure 8-13.

9781430247883_Fig08-13.jpg

Figure 8-13 .  Adding our Java code to MainActivity.java to define and start our image transition

Tip  We have one new import statement to add, so we need to open up the import statements block of code as shown in in Figure 8-13. This can be done by clicking on the plus sign (+) next to the import block of code. The plus sign indicates that this code block can be expanded (just click the +). You can click any of the minus signs (–) in your Java code window to close classes you are finished editing, if you want to see a higher-level view of your code, similar to the Outline Pane view on the right side of the Eclipse IDE. Once your code becomes long and involved, you will find that you will use this simple but powerful code organization feature regularly. Try it, and get used to making it a part of your work process inside of the Eclipse IDE.

This line of code declares our TransitionDrawable object, which we name trans. It sets trans to the results of the call to the getDrawable() method of the object (which retrieves our image_transition XML image transition definition) that is returned to the getResources() method that calls it to get the image resources that will be used by the TransitionDrawable class.

This single line of code essentially declares our trans object for use and also loads the image_transition.xml transition drawable specification into the TransitionDrawable trans object all in one compact line of Java code! Remember that the image_transition drawable resource obtained pointers to our two circular images that we are going to transition between.

Setting up that TransitionDrawable object and loading it with our XML file is the most difficult line of code in this quartet. The next three lines of code are more familiar and a bit more straightforward:

ImageView transImage = (ImageView) findViewById(R.id.imageTrans);
transImage.setImageDrawable(trans);
trans.startTransition(10000);

We create an ImageView object in Java called transImage and, via the findViewById() method, we link it to the imageTrans ID, referenced from the second ImageView XML tag we added earlier to the activity_main.xml file in our /res/layout/ folder. We then use the setImageDrawable() method to set the transImage ImageView object to the trans TransitionDrawable object that we just created above it, linking or “wiring” the two objects to each other, in essence. This is the bridge between the two main objects that allows things to work properly in this image transition section of code.

Finally, we can now talk to the trans TransitionDrawable object via its startTransition(milliseconds) method. We will use that method to tell the transition (once it begins) that we want it to take place over 10,000 ms, or over a 10-second duration (a slow cross-fade).

Select Run As image Android Application and watch all the fun animation begin immediately on App start-up. That’s a lot of animation going on all at once! Be sure your users have decent processing power (dual-core Intel processor is the best, or soon, quad-core processor Android devices) if you choose to place a lot of animation in a single Activity UI screen in your Android application.

Summary

In this chapter, we took a look at the more advanced graphics and animation capabilities that Android offers, including what Android wants to see you using as far as graphic formats are concerned, as well as two different types of animation, and how to code image transitions.

You also learned a little more about the Eclipse IDE, the Android Runnable interface and run() method, and the high-quality WebP, PNG24, and PNG32 image file formats that are optimal for use in Android apps.

Here are some important points to remember:

  • Always use PNG24 format (which is really PNG32 format, if you are using the alpha channel) or you can use WebP, but only if you are supporting Android 4 or later (4.04, 4.1, 5.0).
  • Bitmap animation and tween animation are two completely different things as far as Android is concerned. Bitmap-related animation and transitions are handled through the /res/drawable folder. Tween animation is handled via XML files defined in the /res/anim folder, and can affect other objects besides just bitmap images, such as TextViews.
  • Don’t limit yourself when using tween animation. Use it on any type of View container you like—text, image, video, button, layout, or whatever; wax creative, and be sure to experiment.

In Chapter 9, we’ll start looking at how to make all of what we have been learning about so far become interactive! This is done by setting up our applications to handle events and to listen for those events via event listeners.

We’ll also cover new media assets such as audio and video using the Android MediaPlayer class over the last couple chapters of the book, so your capabilities are going to get more and more powerful! Let’s get interactive with our end-users next, and get right into Chapter 9.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
35.171.45.182