Skinning is the process of changing the appearance of a component by modifying or replacing its visual elements. These elements can be made up of bitmap images, SWF files, or class files that contain drawing methods that define vector images.
Skins can define the entire appearance, or only a part of the appearance, of a component in various states. For example, a Button control has eight possible states, and eight associated skin properties, as the following example shows:
|
State |
Skin property |
Default skin class |
|---|---|---|
|
down |
downSkin |
mx.skins.halo.ButtonSkin |
|
over |
overSkin |
mx.skins.halo.ButtonSkin |
|
up |
upSkin |
mx.skins.halo.ButtonSkin |
|
disabled |
disabledSkin |
mx.skins.halo.ButtonSkin |
|
selectedDisabled |
selectedDisabledSkin |
mx.skins.halo.ButtonSkin |
|
selectedDown |
selectedDownSkin |
mx.skins.halo.ButtonSkin |
|
selectedOver |
selectedOverSkin |
mx.skins.halo.ButtonSkin |
|
selectedUp |
selectedUpSkin |
mx.skins.halo.ButtonSkin |
The default skins for the up, over, and down states appear as follows:
Other controls have similar states with associated skins. For example, RadioButton controls, which are subclasses of Button, also have up, down, and over skins. The ComboBox control has skins the define the appearance of the control when it is in the disabled, down, and over states.
You create a skin by using a bitmap image, a SWF file, or a class defined in ActionScript or in MXML. All Flex components have a default skin class that can represent more than one state of the component. As you can see in the previous table, the eight states of the Button control use the same default skin class, mx.skins.halo.ButtonSkin, to draw the skin. Logic within the class determines the appearance of the Button control based on its current state.
You assign a skin to a component by using style properties. You can set a style property by using MXML tag properties, the StyleManager class, <mx:Style> blocks, or style sheets. Most Flex application use style sheets to organize and apply skins. Style sheets can be loaded at compile time or at run time. For information on loading style sheets at run time, see Loading style sheets at run time.
You typically define a skin as a bitmap graphic or as a vector graphic. Bitmap graphics, called graphical skins in Flex, are made up of individual pixels that together form an image. The downside of a bitmap graphic is that it is typically defined for a specific resolution and, if you scale or transform the image, you might notice a degradation in image quality.
A vector graphic, called a programmatic skin in Flex, consists of a set of line definitions that specify a line's starting and end point, thickness, color, and other information required by Adobe® Flash® Player to draw the line. When a vector graphic is scaled, rotated, or modified in some other way, it is relatively simple for Flash Player to calculate the new layout of the vector graphic by transforming the line definitions. Therefore, you can perform many types of modifications to vector graphics without noticing any degradation in quality.
One advantage of programmatic skins is you can create vector graphics that allow you a great deal of programmatic control over the skin. For example, you can control the radius of a Button control's corners by using programmatic skins, something you cannot do with graphical skins. You can develop programmatic skins directly in your Flex authoring environment or any text editor, without using a graphics tool such as Adobe Flash. Programmatic skins also tend to use less memory because they contain no external image files.
The following table describes the different types of skins:
|
Skin type |
Description |
|---|---|
|
Graphical skins |
Images that define the appearance of the skin. These images can JPEG, GIF, or PNG files, or they can be symbols embedded in SWF files. Typically you use drawing software such as Adobe® PhotoShop® or Adobe® Illustrator® to create graphical skins. For more information, see Creating graphical skins. |
|
Programmatic skins |
ActionScript or MXML classes that define a skin. To change the appearance of controls that use programmatic skins, you edit an ActionScript or MXML file. You can use a single class to define multiple skins. For more information, see Creating programmatic skins. |
|
Stateful skins |
A type of programmatic skin that uses view states, where each view state corresponds to a state of the component. The definition of the view state controls the look of the skin. Since you can have multiple view states in a component, you can use a single component to define multiple skins. For more information, see Creating stateful skins. |
When using graphical skins, you must embed the image file for the skin in your application. To specify your skin, you can use the setStyle() method, set it inline, or use Cascading Style Sheets (CSS), as the following example shows:
<?xml version="1.0"?>
<!-- skins/SimpleButtonGraphicSkin.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style>
Button {
upSkin: Embed("../assets/orb_up_skin.gif");
}
</mx:Style>
<mx:Button id="b1" label="Click Me"/>
</mx:Application>
The executing SWF file for the previous example is shown below:
For information on setting skins by using the setStyle() method or by setting them inline, see Applying skins.
You can assign the same graphic or programmatic skin to two or more skins so that the skins display the same image, as the following example shows:
<?xml version="1.0"?>
<!-- skins/SimpleButtonGraphicSkinTwoSkins.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style>
Button {
upSkin: Embed("../assets/orb_up_skin.gif");
overSkin: Embed("../assets/orb_up_skin.gif");
}
</mx:Style>
<mx:Button id="b1" label="Click Me"/>
</mx:Application>
The executing SWF file for the previous example is shown below:
For more information, see Creating graphical skins.
You can define programmatic skins in either MXML or ActionScript. When using programmatic skins, you can define a class for each state of the component, or define a single class for multiple skins. In the following example you create a custom ActionScript skin to define the skin for the up state of the Button control:
package {
// skins\ButtonUpSkinAS.as
import mx.skins.ProgrammaticSkin;
public class ButtonUpSkinAS extends ProgrammaticSkin {
// Constructor.
public function ButtonUpSkinAS() {
super();
}
override protected function updateDisplayList(unscaledWidth:Number,
unscaledHeight:Number):void
{
graphics.lineStyle(1, 0x0066FF);
graphics.beginFill(0x00FF00, 0.50);
graphics.drawRoundRect(0, 0, unscaledWidth, unscaledHeight, 10, 10);
}
}
}
In ActionScript, you typically use the ProgrammaticSkin class as the base class for your skin. In the skin class, you must override the updateDisplayList() method to draw the skin. You then assign the skin component to the appropriate skin property of the Button control using a style sheet, as the following example shows:
<?xml version="1.0"?>
<!-- skins/ApplySimpleButtonSkinAS.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style>
Button {
upSkin: ClassReference("ButtonUpSkinAS");
}
</mx:Style>
<mx:Button id="b1" label="Click Me"/>
</mx:Application>
The executing SWF file for the previous example is shown below:
For information on applying skins, see Applying skins.
In the following example you create a custom MXML component to define the skin for the up state of the Button control. In MXML, you use ProgrammaticSkin as the base class of your skin. This is the same skin defined above in ActionScript:
<?xml version="1.0"?>
<!-- skins\ButtonUpMXMLSkin.mxml -->
<skins:ProgrammaticSkin xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:skins="mx.skins.*">
<mx:Script>
<![CDATA[
override protected function updateDisplayList(unscaledWidth:Number,
unscaledHeight:Number):void
{
graphics.lineStyle(1, 0x0066FF);
graphics.beginFill(0x00FF00, 0.50);
graphics.drawRoundRect(0, 0, unscaledWidth, unscaledHeight, 10, 10);
}
]]>
</mx:Script>
</skins:ProgrammaticSkin>
Notice that you have to include the xmlns:skins="mx.skins.*" namespace declaration in MXML. This is necessary because by default you cannot use the ProgrammaticSkin class as the base class of an MXML component.
In the following example, you create a component that defines skins for multiple Button states. In this example, you use a case statement to determine the current state of the Button control based on the name property of the skin, where the name property contains the current name of the skin. For example, if you define a programmatic skin for a Button control, the name property could be any of the skin states: downSkin, upSkin, overSkin, disabledSkin, selectedDisabledSkin, selectedDownSkin, selectedOverSkin, or selectedUpSkin.
package {
// skins\ButtonUpAndOverSkinAS.as
import mx.skins.ProgrammaticSkin;
public class ButtonUpAndOverSkinAS extends ProgrammaticSkin {
// Constructor.
public function ButtonUpAndOverSkinAS() {
super();
}
override protected function updateDisplayList(unscaledWidth:Number,
unscaledHeight:Number):void
{
switch (name)
{
case "upSkin": {
graphics.lineStyle(1, 0x0066FF);
graphics.beginFill(0x00FF00, 0.50);
graphics.drawRoundRect(0, 0, unscaledWidth, unscaledHeight, 10, 10);
}
case "overSkin": {
graphics.lineStyle(1, 0x0066FF);
graphics.beginFill(0x00CCFF, 0.50);
graphics.drawRoundRect(0, 0, unscaledWidth, unscaledHeight, 10, 10);
}
}
}
}
}
You then assign the ActionScript class to the appropriate skin properties:
<?xml version="1.0"?>
<!-- skins/ApplyButtonUpOverSkinAS.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style>
Button {
upSkin: ClassReference("ButtonUpAndOverSkinAS");
overSkin: ClassReference("ButtonUpAndOverSkinAS");
}
</mx:Style>
<mx:Button id="b1" label="Click Me"/>
</mx:Application>
The executing SWF file for the previous example is shown below:
For more information on creating programmatic skins, see Creating programmatic skins.
When using a stateful skin, you define a skin that defines a view state for each state of a component. In the following example, you define a view state for the up and over states of a Button control:
<?xml version="1.0"?>
<!-- skins\ButtonUpStatefulSkin.mxml -->
<mx:UIComponent xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
private var _rectFill:uint = 0x00FF00;
public function get rectFill():uint {
return _rectFill;
}
public function set rectFill(value:uint):void {
_rectFill = value;
invalidateDisplayList();
}
override protected function updateDisplayList(unscaledWidth:Number,
unscaledHeight:Number):void
{
graphics.lineStyle(1, 0x0066FF);
graphics.beginFill(rectFill, 0.50);
graphics.drawRoundRect(0, 0, unscaledWidth, unscaledHeight, 10, 10);
}
]]>
</mx:Script>
<mx:states>
<mx:State name="up"/>
<mx:State name="over">
<mx:SetProperty target="{this}"
name="rectFill" value="0x00CCFF"/>
</mx:State>
</mx:states>
</mx:UIComponent>
You typically define a stateful skin as a subclass of UIComponent, in ActionScript or in MXML, because the view state mechanism is built into the UIComponent class. For more information, see Creating stateful skins.
You can create a stateful skin in either ActionScript or MXML. This examples uses MXML because it requires fewer lines of code to define view states. You then assign the MXML component to the skin property of the Button control, as the following example shows:
<?xml version="1.0"?>
<!-- skins/SimpleButtonStatefulSkin.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style>
Button {
skin: ClassReference("ButtonUpStatefulSkin");
downSkin: ClassReference("mx.skins.halo.ButtonSkin");
disabledSkin: ClassReference("mx.skins.halo.ButtonSkin");
selectedUpSkin: ClassReference("mx.skins.halo.ButtonSkin");
selectedOverSkin: ClassReference("mx.skins.halo.ButtonSkin");
selectedDownSkin: ClassReference("mx.skins.halo.ButtonSkin");
selectedDisabledSkin: ClassReference("mx.skins.halo.ButtonSkin");
}
</mx:Style>
<mx:Button id="b1" label="Click Me"/>
</mx:Application>
The executing SWF file for the previous example is shown below:
When using stateful skins, you must explicitly specify the default skin for all states not defined by the stateful skin component.
Before a component applies a skin, it first determines its size without the skin. The component then examines the skin to determine whether the skin defines a specific size. If not, the component scales the skin to fit. If the skin defines a size, the component sizes itself to the skin.
Most skins do not define any size constraints, which allows the component to scale the skin as necessary. For more information on writing skins that contain size information, see Implementing measuredWidth and measuredHeight getters.
In some cases, you want to reskin subcomponents. The following example reskins the vertical ScrollBar control that appears in List controls:
<?xml version="1.0"?>
<!-- skins/SubComponentSkins.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script><![CDATA[
[Bindable]
private var theText:String = "Lorem ipsum dolor sit amet, consectetur " +
"adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore " +
"magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco " +
"laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor " +
"in reprehenderit in voluptate velit esse cillum dolore eu fugiat " +
"nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt " +
"in culpa qui officia deserunt mollit anim id est laborum.";
]]></mx:Script>
<mx:Style>
.myScrollStyle {
upArrowUpSkin: Embed("../assets/uparrow_up_skin.gif");
downArrowUpSkin: Embed("../assets/downarrow_up_skin.gif");
}
</mx:Style>
<mx:TextArea id="ta1"
width="400"
height="50"
verticalScrollPolicy="on"
verticalScrollBarStyleName="myScrollStyle"
text="{theText}"
/>
</mx:Application>
The executing SWF file for the previous example is shown below:
By setting the value of the verticalScrollBarStyleName property in the List type selector, all vertical ScrollBar controls in List components have a custom skin. The ScrollBar controls in other parts of the application do not have the custom skin.
As with all style sheets, you can define the skins in a separate CSS file and use the source property of the <mx:Style> tag to point to that file; for example:
<mx:Style source="../stylesheets/MySkins.css"/>
A theme is a collection of style definitions and skins that define the look and feel of a Flex application. Theme files can include both graphical and programmatic skins, as well as style sheets.
A theme takes the form of a SWC file that can be applied to a Flex application. You compile a SWC file using the compc command-line compiler utility.
By compiling a SWC file and then using that SWC file as a theme in your application, you remove the burden of compiling all the skin files when you compile your main application. This can make compilation faster and make problems with the application code easier to debug. In addition, a SWC file is easier to transplant onto another application than are a set of classes and image files.
Halo, the default theme set that ships with Flex, is almost entirely made up of programmatic skins, although there are some static graphic elements. Flex includes programmatic and graphical skins that use the Halo look and feel. You can edit the skins by using either the programmatic or graphical technique to reskin Halo components.
For more information on creating and applying themes, see About themes.
Flex includes the following graphical and programmatic source files for skins:
Base skin classes in the mx.skins package
These abstract skin classes define the basic functionality of skin classes in Flex. For more information, see Creating programmatic skins.
Programmatic Halo skins in the mx.skins.halo package
These concrete skin classes extend the base skin classes in the mx.skins package. You can extend or edit these skins to create new programmatic skins based on the default Flex look and feel. For more information, see Creating programmatic skins.
HaloClassic skins
These skins were used in Flex 1.x. You can retain the look of Flex 1.x applications by using these skins. The HaloClassic.swc file is located in the framework/themes directory. For more information, see About themes.
Graphical Aeon theme
The Aeon theme includes the AeonGraphical.css file and the AeonGraphical.swf file that defines the skin symbols. These are in the framework/themes directory. In addition, Flex includes the FLA source file for the AeonGraphical.swf file. For more information, see About themes.
You use these files to create skins based on the Flex look and feel, or create your own.
You can create graphical, programmatic, and stateful skins for Adobe Flex applications by using Adobe® Flash® CS3, Adobe Illustrator CS3, Adobe Photoshop CS3, and Adobe® Fireworks® CS3. To create skins by using these tools, first download and install extensions that simplify the skinning process. These extensions include the skin templates for all Flex components. For more information on using these tools to create skins, and to download the required extensions, see http://www.adobe.com/go/flex3_cs3_skinning_extensions.
While the Flex skinning extensions provide tools that make it easy to create skins in Flash CS3, such as the template of all Flex skins, you are not required to use them to create skins in Flash CS3. Flex lets you use the [Embed] metadata tag to import a skin class into a Flex application from a SWC file created in Flash CS3.
Creating a skin class in Flash CS3
Set the following properties on the movie clip symbol:
Embed the skin class in a Flex application
The [Embed] metadata tag has the following syntax for skin classes created in Flash CS3:
[Embed(skinClass="className")]
For example, if you create a skin named Button_upSkin for the up skin of the Flex Button control, embed the skin as the following example shows:
<mx:Style>
Button
{
upSkin: [Embed(skinClass="Button_upSkin")]
}
</mx:Style>