As mentioned before, you can add media to an application by either
loading it or embedding it. In this section, we will discuss the different
syntax for loading and embedding media. This will serve as a good
foundation for understanding the methods you have available to you when
adding media to a Flex application. In the Flex framework, watch for
component properties that accept a variable of type Class
. These properties usually indicate the
ability to accept a media type as a value.
If you have experience with developing Flash applications, you may be accustomed to creating classes for symbols such as images for when you want to access them in ActionScript. In Flex, this is no longer required as the compiler generates such classes for you automatically.
The easiest and most common way to load media at runtime is to use
one of the MXML components specifically designed for that job. A variety
of components are available for different types of media. You can use an
Image
component to load images, an
SWFLoader
component to load .swf files, or a VideoDisplay
component to load video content. The Image
component is
the most commonly used of these components and the one we will focus on
in this section.
Internally, Flex makes use of Flash Player’s Loader
class. You typically will not make
use of the Loader
class directly as
the Flex framework abstracts away the details, but it is good to know
that it exists and that if you ever need to implement the loading of
custom file types not supported by Flex, you can easily do so.
Here is an example that uses an Image
tag to load a .jpg file:
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"> <mx:Image source="assets/sun.jpg"/> </mx:Application>
This simple code loads an image file called sun.jpg located in an assets directory relative to the .swf at runtime and displays it in an
Image
component. The JPEG file format
is natively supported by Flash Player; as such, you are able to load it
at runtime. Also important to note is that the application .swf does not contain the image; rather, it
begins to load after the application is initialized. This behavior is
very similar to how web browsers load images that are referenced in an
HTML document.
Loaded assets are referenced at runtime based on the location of the .swf file by default. You can reference assets using both absolute and relative paths.
This example uses the Image
component, which is a Flex component built to help you easily load
images. The Image
component loads the
image provided by the source attribute and sizes it according to the
width
and height
properties of the Image
component instance, if any are provided.
If no size is specified, the component expands to the dimensions of the
image. Also, the Image
component by
default loads whatever you set in the source
property. If you want to load the image
based on user input or an event, you can call the load()
method of the Image
instance at runtime, or you can
data-bind the source
property to a
variable that stores the image you would like to load. Here is an
updated example of the preceding code that provides users with a button
to load the image when they want to view it, with no explicit width
or height
properties set:
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"> <mx:Image id="sun"/> <mx:Button label="Load Image" click="sun.load('assets/sun.jpg')"/> </mx:Application>
This version of the application does not automatically load the
image, as before. The Image
component
instance exists, but it loads the image only after the application is
initialized. Also, the source
property has no value in this example. When you do not specify the
source
property for an Image
instance, the component will not load an
image automatically. When a user clicks on the button in the example,
the load()
method is called, along
with the value of the image to load as a parameter.
The Image
component along with
the SWFLoader
and VideoDisplay
components dispatch events to
indicate the status of the component. The Image
component dispatches many events; the
ones related to loading content are the ioError
, progress
, open
, httpStatus
, securityError
, and complete
events.
The Flex framework components use the underlying Flash Player
API to load media. To learn the internal details about the
underlying mechanism that Flex uses to load content, review the
documentation on the Loader
class in
the flash.display
package and the
LoaderInfo
class. An instance of the LoaderInfo
class is exposed by all three
components.
The events you’ll be most interested in are progress
, complete
, and ioError
. The progress
event is dispatched while an asset is being loaded. This allows
you to provide the user with a progress bar or some other indication
that something is loading. This is especially useful when loading a lot
of content or large content. The complete
event allows you to determine when an
asset has finished loading. This can be useful if you want to provide
some sort of notification to the user, or have another process begin
after the content is loaded. The ioError
event is important when having to deal with content that may or
may not exist, especially if the user is asked to enter his own URL, for
example. The ioError
event is
dispatched when Flash Player is unable to find the referenced file,
allowing you to provide the user with the option of reentering the URL.
An error is usually reported immediately if the client receives a
response from the server that shows an error such as File Not Found, but
if you reference a server that can't be reached, the response won't be
returned in a timely manner, if ever.
The code in Example 11-1 allows a user to enter a URL of an image to be loaded and notifies the user if he has entered an invalid URL.
Example 11-1. Notifying the user of an invalid URL
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"> <mx:Script> <![CDATA[ import mx.controls.Alert; private function ioErrorHandler():void { Alert.show("There was an error loading: "+imageUrl.text+", please enter a new URL"); } ]]> </mx:Script> <mx:Image id="imageView" ioError="ioErrorHandler()"/> <!--when compiled and run locally, you can load remote images without security restrictions that are typically encountered with an application running in the browser sandbox --> <mx:TextInput id="imageUrl" text="http://www.google.com/intl/en/images/logo.gif"/> <mx:Button label="Load image" click="imageView.load(imageUrl.text)"/> </mx:Application>
When embedding media, you instruct the compiler to package the asset within the resultant .swf file rather than just referencing it externally, as you saw in the preceding section. In other platforms, such as Java and .NET, this is sometimes referred to as compiling the asset as a resource. You can embed media within the following types of content:
MXML
ActionScript
CSS
You embed media by using any of these three variations of the
Embed()
directive. This directive
accepts the source
, mimeType
, scaleGridTop
, scaleGridBottom
, scaleGridLeft
, scaleGridRight
, and symbol
parameters. The parameter you will use
most often—and the only parameter that is required—is source
. This parameter identifies to the
compiler the asset it needs to process and embed within the final
.swf file.
The embed syntax when used in MXML begins with an @Embed()
directive. The @
character instructs the compiler that it
will be receiving a directive in MXML—in this case, the Embed()
directive.
Earlier you saw an example of how to load a .jpg asset at runtime. Now we’ll look at how to embed the asset:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Image source="@Embed(source='assets/sun.jpg')"
/>
</mx:Application>
This example should look very similar to the earlier example,
except for the additional syntax within the value of the source
attribute. This syntax, when used
within MXML, instructs the compiler to embed an asset rather than load
it.
When embedding an asset, the compiler will not resize or recompress the media contained with the resultant SWF. It will embed the asset as is in its original form. If you intend to use an asset only at a specific size, you should match in the source the final size that will be used in the application.
Sometimes you will want to embed your assets in ActionScript. This allows you to reference them directly within ActionScript, or even reference the embedded asset from MXML. Embedding media in ActionScript has the same result as doing so in MXML, but can be more flexible, as we will see later in this chapter when we cover how to create an asset library; the only difference is that the compiler instructions for embedding are in ActionScript code. Example 11-2 shows the code from Example 11-1, but in ActionScript.
Example 11-2. Displaying an image using an Image component while embedding it in ActionScript
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"initialize="init()"
> <mx:Script> <![CDATA[ [Embed(source="assets/sun.jpg")] private var sunAsset:Class; //This method is called when the application is initialized private function init():void { sunImage.source = sunAsset; } ]]> </mx:Script> <mx:Imageid="sunImage"
/> </mx:Application>
The main difference between Example 11-1 and Example 11-2 is that a change
in the value of the source
property
for the Image
instance is being set
through ActionScript. When embedding content, you must assign data of
type Class
to the source
property. You don’t typically specify a class yourself; instead,
the Flex compiler automatically generates such a type for you when you
embed an asset. When embedding content, you will need to reference a
variable declared with the [Embed()]
metadata syntax. The contents of
the Embed()
directive in Example 11-2 are the same as
in Example 11-1. In
ActionScript, Embed()
must be
surrounded by []
. This is called a metadata
tag, and it instructs the compiler that it needs special
handling. The Embed
metadata tag
must precede the variable declaration, as shown in Example 11-2. Once done, the
value of the variable will be the reference asset in the Embed()
directive.
The declared variable of an asset must be of type Class
. Placing an Embed
metadata tag before the variable will
cause the compiler to define the variable’s class definition and allow
you to instantiate it or reference it when you need to work with the
asset. Although the variable is declared as a generic Class
data type, each type of media asset
maps to a more specific class definition, depending on the type of
media embedded. All asset class types implement a common interface,
IFlexAsset
.
The different types of asset classes are as follows:
BitmapAsset
, which
represents bitmap images (JPEG, GIF, and PNG).
MovieClipAsset
, which
represents Flash library items within an SWF. Typically, such an
asset is an animated graphic. For static (nonanimated) SWF library
items, SpriteClass
is
used.
MovieClipLoaderAsset
,
which represents SWF files.
SoundAsset
, which
represents an embedded MP3 file.
SpriteClass
, which
represents a static vector graphic from an SWF library item or SVG
file.
ButtonAsset
, which is
rarely used but is provided to ensure full compatibility with
Flash authoring content.
TextFieldAsset
, which
will never be produced by Flex, but is produced by other tools
such as Flash authoring.
One of the strengths of using ActionScript for part of an application is the added flexibility it gives you when handling application logic at runtime. In that spirit, let’s take a look at Example 11-3, which allows us to change an embedded image at runtime.
Example 11-3. Changing the embedded asset to be displayed at runtime
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" initialize="init()"> <mx:Script> <![CDATA[ [Embed(source="assets/sun.jpg")] private var sunAsset:Class; [Embed(source="assets/moon.jpg")] private var moonAsset:Class; private function init():void { sunImage.source = sunAsset; } private function showMoon():void { sunImage.source = moonAsset; } ]]> </mx:Script> <mx:Image id="sunImage"/> <mx:Button label="Show the Moon!" click="showMoon()"/> </mx:Application>
In Example 11-3,
the sun image asset is initially displayed, and the user is presented
with a button to display the moon image. The button’s click
event is set up to call the showMoon()
function, which will set the
source
property of the Image
instance to the moonAsset
that contains the embedded image.
When you declare an asset to be embedded, that asset is included
within the final .swf file
regardless of whether it is used. This means that when referencing
different embedded assets, those assets will not need to be
loaded.
Typically, you embed assets when stylizing and skinning
components. So far, we have discussed using the Image
component to load and embed images.
The Image
component is ideal for
loading and displaying images and animations. With CSS, though, you
can easily specify component skins.
Example 11-4 is an example of embedding assets to reskin a button component using CSS.
Example 11-4. Skinning a Button component by embedding in CSS
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"> <mx:Style> Button { down-skin:Embed(source="assets/btnDown.PNG"); over-skin:Embed(source="assets/btnOver.PNG"); up-skin:Embed(source="assets/btnUp.PNG"); } </mx:Style> <mx:Button label="Hello World!"/> </mx:Application>
Example 11-4
showcases the power of Flex in terms of handling CSS and embedding
assets. In this example, we redefined the base skin for all instances
of the Button
component within
three lines (you can find more information on skinning components in
Chapter 8). We did this by
setting the values of the CSS properties to images that we embedded.
The syntax is similar to that used in Example 11-3 and Example 11-2. In CSS, though,
you don’t need to use identifier characters as you do with the other
two forms of syntax. In CSS, you just use the Embed()
directive directly inline.