The Macromedia Flash MX 2004 components have come a long way in functionality from previous versions. One of the areas that have been completely re-thought is the possible skinning mechanisms. Although the new components offer many options and are more flexible than in previous versions, it hasn’t been easy to realize the benefits.
In this article I explore skinning components using the many skinning options
available. I cover skinning using the library and themes, and through code
I explore skinning using the prototype method, subclassing a component class,
and the initObject method. Armed with this, you will be able to
take better control of your application's look and feel and have a good understanding
of how flexible the new skinning architecture is in Flash MX 2004.
To make the most of this article, you need the following:
The Flash MX 2004 components are based on the Version 2.0 component framework, the latest framework provided by Macromedia. One of the many changes the new framework required is a re-thinking of how components will support skinning. In the previous version of Flash, there wasn’t much of a formal system behind how skinning was implemented. Generally component developers just made sure that they had movie clips in the library for when a component needed to display something. In that way a user could easily edit a library symbol if they wanted to change the look of a component. This was very simple for users, but also very limited.
As you might have guessed, a simple approach has many drawbacks. The biggest of which was the ability to skin different instances of a component separately and have control over skinning through code. Since all instances shared the same library symbol, instance-level skinning wasn’t possible (at least not without a lot of extra work). Furthermore skinning required you to work with the library and didn’t provide you with other options. With the new component framework, users have a lot more flexibility over how they can skin components. With this added flexibility though comes greater complexity, which requires a solid understanding of the many options to best take advantage of the skinning architecture.
It's important to understand the way that component skins are used by components
to help us deal with the available options. It would be ideal if the components only
supported one method of skinning and that method is exactly what we wanted all the
time. However, that is pretty tough to achieve without leaving out some users. I usually
use the initObject method through code to skin components, as well as the sub-classing
method, but that may not always work for your needs.
To begin, you must understand the basics of what ties everything together. In Flash, every component skin is identified by a Linkage ID in the library that the component code uses to attach a skin at runtime. That Linkage ID is a unique identifier that a component will use to identify a skin (which usually translates to a specific state).
For example in a Button component you have many states, each state can have its own skin, which the component will use. States can be any visual state the component has to represent, something like Rollover, Press, and RollOut. Knowing the available skin properties for each component is important. You can find this information in the documentation as well as look through the component code (in the code, they are declared as private member variables. In the component documentation section for each component, you will find a section titled "Customizing the [component name]." In that documentation entry you will find two main sections, one section is titled " Using skins with the [component name]." That section will list the different skin properties (component properties) and provide a brief description of each one.
Note: I highly recommend you obtain the latest update to Flash MX 2004, version 7.2 (Ellipsis), which includes the most up-to-date documentation. The documentation for skinning each component has been updated and improved.
Visually skinning components usually involves modifying library symbols to represent what you want a component to look like. Many long-time Flash users were surprised that they couldn't readily find component symbols in the library when including a component in their project.
The introduction of the SWC (a compiled form of a component that is used to package all component assets into one convenient file) file format in Flash MX 2004 allowed us to easily package components and distribute them, which is a great benefit. At the same time, however, the skins, which are required for each component, are also included in the SWC. Since you can't edit the contents of an SWC file, you must add the library symbols to redefine those symbols.
By adding symbols to your library with the same linkage IDs that the skin property is set to (usually the default value of the component), a component would use that symbol over the symbol included within the SWC file for its skin. You might be thinking this is a pretty tedious task (i.e., manually tracking down the Linkage IDs, creating each symbol, and making sure you don't make mistakes along the way), but thankfully Macromedia has provided us with a starting point to help ease the process.
The StandardComponents.FLA file is included with every installation of Flash and is located in C:\Program Files\Macromedia\Flash MX 2004\en\Configuration\ComponentFLA (Windows) and Hard Drive/Users/ <username>/Library/Application Support/Macromedia/Flash MX 2004/ en/Configuration/ComponentFLA (OS X).
In the latest version of Flash, Macromedia introduced the concept of themes. Before I discuss using themes to skin components, I'll briefly explain the purpose of themes.
Themes are a collection of skins and styles that enable you to develop an overall look for a set of components. I will not look into how styles are implemented in themes, because my main focus is skinning. Themes work as mentioned above, by having a symbol in the library with the same Linkage ID as existing symbols within the component's SWC. To make use of themes, Macromedia distributes the collection of library symbols in an FLA file as a starting point to work from.
The following steps explain how to include a theme:
Customize the different graphical items in the symbol to your liking (see Figure 1).
Figure 1. My Customized Window Assets Symbol
Typically you would customize all the different symbols in a theme and have the complete theme available so you can easily reskin an application. Note also that at this time theme files are not only made up of graphical assets in the library, but can also be drawn through code including default component style values, as I will show shortly.
To briefly discuss styles in themes, you can check the HaloTheme library. You will
notice a symbol called Defaults in Flash UI Components 2 > Themes > MMDefault
of the library. If you check the linkage properties of the symbol you will find that
the symbol is associated with a class. You can find that class files in the included
Classes folder. Open the Default.as file located in C:\Program Files\Macromedia\Flash
MX 2004\en\First Run\Classes\mx\skins\halo (Windows) or (OS X) . You should know that
the setThemeDefaults() method is responsible for setting these defaults. If you want
to build a complete theme, you might find it beneficial to specify the default styles
of components as well. You can do so easily by customizing the Default.as file. If you
plan to do so, ensure you create a local copy for your application. The files located
in the global classes folder should never be modified.
Finally, if you want to skin only one component rather than have a whole theme, you could delete all library item files not related to the component you are interested in skinning and edit the symbol you want instead.
Skinning components without any code can be very limiting, but there are several things to keep in mind when trying to avoid writing code every time you want to skin a component:
For example, explore the file SampleTheme.fla which can be found in C:\Program Files\Macromedia\Flash MX 2004\en\Configuration\ComponentFLA (Windows) or Hard Drive/Users/<username>/Library/Application Support/Macromedia/Flash MX 2004/en/Configuration/ComponentFLA (OS X). This theme can be easier to skin because it uses less code to draw the skins as apposed to the HaloTheme
Some components use the same values for multiple skin properties (component states), as they draw that skin using code. For those components, there is no method of customizing the different states independently without having to write some code. The Button component is a good example of this.
In general, if you want more control over your skinning, you must use code. In some cases, this method also offers skinning options not available in the previously studied methods. Some methods are quite simple, while others can be quite involved.
The prototype method is the easiest coding method. This method involves writing code
that redefines the default value of skin properties.
Take the Button component, for example. If you wanted to set the four main values for skin properties ( falseUpSkin, falseDownSkin, falseOverSkin, falseDisabledSkin) you would do the following (the finished result can be found in the Prototype folder of the downloadable sample code):
Be sure the Linkage identifier is set for each state; usually its best to follow some standard naming convention. For this example, I use the BlueButtonUpSkin, BlueButtonDownSkin, BlueButtonOverSkin, and BlueButtonDisabledSkin identifiers (see Figure 2).
Figure 2. The completed Linkage Properties dialog box for the BlueButtonUpSkin identifier
Notice that I didn't set the symbol to export in the first frame. If you don't mind exporting all your symbols on the first frame, then you can leave the Export in first frame checkbox selected and skip to step 7.
stop() function call.Place the four symbols you created in step 2 on the second frame (see Figure 3).
Figure 3. The completed FirstFrameExporter symbol
Finally, you need to place the code that will set the values of the properties equal to the Linkage IDs. The easiest way is to open the FLA file, go to the main Timeline, and enter the following code:
mx.controls.Button.prototype.falseUpSkin = "BlueButtonUpSkin"; mx.controls.Button.prototype.falseDownSkin = "BlueButtonDownSkin"; mx.controls.Button.prototype.falseOverSkin = "BlueButtonOverSkin"; mx.controls.Button.prototype.falseDisabledSkin = "BlueButtonDisabledSkin";
This method is the simplest method for skinning components through code. It has the benefit of enabling you to redefine the skin property values of all instances of a component in one place. With the previous example, all Buttons added to our project will use those new default values rather than the default values the component was originally set to.
This method also has the advantage of enabling you to set skin property values for subcomponents of a component. A good example of this use is the ComboBox component, which uses a ListBox component. If you set the skin property values for a ListBox using this method, the ComboBox ListBox will automatically use the new value.
However, this method has one downside, which may not affect you—the ability to skin a component on an instance basis. Many times this is not needed, but there are times when you want to set the skin property values of a component specifically for that instance. In that case, you can use one of the other methods that require code.
Another approach similar to the using the prototype method is passing in the new
skin property values to the initObject object when attaching a component through code,
rather than setting them through the prototype method. To achieve this method, you
can follow these steps:
On the main timeline, create an initObject object with the properties and values
of the skin properties and pass the object to the createClassObject() calls, using
the following code:
var initObj:Object = new Object(); initObj.falseUpSkin = "BlueButtonSkin"; initObj.falseDownSkin = "BlueDownSkin"; initObj.falseOverSkin = "BlueOverSkin"; initObj.falseDisabledSkin = "BlueDisabledSkin"; createClassObject(mx.controls.Button,"myButton",1,initObj);
This method offers several benefits. For example, it enables you to specify the values on a per component instance basis. Although some applications can live with a single skin per component, often you run into situations where you need that extra level of control.
This method does have some drawbacks though. The most obvious is the requirement to specify this information for each and every instance of a component. It can sometimes get tedious to do this for each component you plan to use. Another requirement is having to attach the component through code. I almost always attach my components through code, but for times when you want to place a component on the Stage, this method won't work.
Overall, I prefer to use a mixture of the method described in this section and the
prototype method in my applications. It's a personal preference, but I've found that
using the prototype method I can define global settings, and the per instance method
enables me to override those values for the times in my application where the component
will not use the values set using the prototype method.
The last method that I want to discuss is subclassing a component class to define the skin property values. This approach enables you to create a subclass of the component that doesn't do anything but define new skin property values.
Follow these steps:
Locate the Button component base symbol (Main Button component symbol) in the file StandardComponents.fla and drag it to the library folder you created in step 4. The symbol is located in Flash UI Components 2 of the library. Your Library panel now should look similar to Figure 4.
Figure 4. Completed copying of Button component-related symbols
Specify an identifier and a class for the duplicated symbol. For this example, I used com.rewindlife.controls.MyButton for both and cleared the Export in first frame check box (see Figure 5).
Figure 5. Completed Duplicate Symbol dialog box
Create four skins for the different states of the Button and include the linkage
identifier as you did in steps 1 and 2 of the prototype method. Alternatively, you
could also copy the symbols from the library of the prototype method example to
this one.
The library should now look like Figure 6.
Figure 6. Added Skins and MyButton symbol
Double click the MyButton symbol and locate the second frame of the assets layer. Drag the four new skins and place them on the second frame to ensure they are exported properly when Flash is ready to compile your new skinned component (see Figure 7).
Figure 7. The MyButton symbol with the skins
Now you have completed all the work you need to do before writing any code. The last step is to write your component class which will be a subclass of the Button class.
Create a new folder to place your class in the proper package (in this example, the package is com.rewindlife.controls, so you will create com/rewindlife/controls folder structure) and create a new ActionScript file called MyButton.as and save it in that folder (see Figure 8).
Figure 8. The Folder structure with new class file
In the MyButton.as file include the following code:
//It is good practice to include this information
//and in some instances it is required
import mx.controls.Button
class com.rewindlife.controls.MyButton extends Button
{
//these values are required for every components,
//we set the symbolName equal to the symbol identifier
//of our components
//
//We set the symbol ownder equal to the fully qualified
//class name.
//
//We can copy these values from the original Button class
//as a starting point, the Class file can be found here:
//C:\Program Files\Macromedia\Flash MX 2004\en\First Run\Classes\mx\controls
//
static var symbolName:String = "com.rewindlife.controls.MyButton";
static var symbolOwner = com.rewindlife.controls.MyButton;
//Here we define the SkinIDs, again we can easily open the
//Button class and copy/paste the current values as a good
//starting point
var falseUpSkin:String = "BlueButtonUpSkin";
var falseDownSkin:String = "BlueButtonDownSkin";
var falseOverSkin:String = "BlueButtonOverSkin"
var falseDisabledSkin:String = "BlueButtonDisabledSkin";
}
As you have seen, this method is the most involved of the coding methods to set up.
It might not seem worth it at first, but it definitely has several benefits. For
example, it enables you to create different buttons and easily re-use a button without
having to redefine the skin property values each time (as you would have to do with
the initObject method).
I like to use this method when I am working on a project with multiple interfaces, and those interfaces will share certain common skin property definitions. With this method I can create a Button and re-use it through all the projects without having to rewrite anything. If I ever want to change the skin property values for that component later on, I can edit that single class file and re-export all my interfaces with the updated values. This is also the only coding method that enables me to use components that are skinned through code without any code (that is, once this method is set up).
When working in teams, developers may at times set up such components for designers to give designers access to the component. You can also package your new component as a SWC file with this method, if you want. In larger teams this can prove to be a very valuable benefit.
So far you have used a graphical symbol in the library to represent a specific skin. This approach is the simplest and provides a straightforward approach, but you should at least know of another option, one that enables you to write code to render a skin rather than a static graphical image.
In the default theme (Halo) that is provided with Flash, Macromedia makes extensive use of code to render a skin rather than static graphics in the library. So what are the benefits to this approach? The biggest benefit of using code to render a skin is the ability to have more control over how a skin resizes. Usually when you create custom skins for your own use, you know the target size and thus can easy build them. Macromedia, however, wanted to build skins that would scale well and render beautifully regardless of the size of the component.
Another benefit can be a more flexible method of skinning through manipulating the library. Take, for example, the Button component. It requires a skin for every state, and those skins need to match the size of the target size of the component when used or you will end up with disproportionate graphics. To deal with this you could either have a skin that is drawn through code, or actually have a skin that does some calculation and attaches multiple graphic symbols.
You've come a long way in exploring the various methods for skinning Flash components. Hopefully, you have a better understanding now of your options and can easily skin components within your application.
Chafic Kazoun is the founder and Chief Software architect at Atellis, and is widely considered one of the world's top experts on Flex (outside of the Adobe Flex engineering team). He has worked with Flash technologies since 1998 and with Flex since its inception, and he has a deep understanding of the internals of the Flex framework. He maintains a busy speaking and consulting schedule. When he's not busy developing solution-based applications, Chafic is actively involved in the Flash community, delivering presentations at numerous conferences including Adobe's MAX, Flashforward, FITC, Spark Europe, and MXDU. He is also the contributor of numerous published works and is the author of Programming Flex 2.0, a book recently released by O'Reilly Publishing. He is also an Adobe Community Expert, and shares his thoughts on his blog.