Requirements

   
Prerequisite knowledge
A basic understanding of creating applications in Flash Builder and Flex is recommended.
 
User level
Intermediate
 
Required 
Flash Builder (Download trial)
Sample files
The Flex 4 SDK introduces new programming tools that make it easier than ever before to define the visual presentation of your web and desktop applications. These tools include a new skinning architecture that lets you define reusable skin components, which can be applied to applications and components both during compilation and at runtime. The skinning architecture is based on a new class named Skin, and a subclass named SparkSkin.
 
Once you configure an application or component to use one of these new skins, you can use traditional graphic files in JPG,.jpg,.jpg or SWF format to define the application or component’s look, or you can use new ActionScript classes that are included in the Flex 4 SDK that, when declared with MXML, mimic the syntax of the new FXG language – an XML-based language that defines low-level graphics, which are then rendered by Flash Player.
 
In this tutorial, I’ll show you how to create a great-looking desktop application that can be deployed with Adobe AIR. You’ll complete the following tasks:
 
  • Create a skin component suitable for use with the new Spark version of the WindowedApplication component
  • Bind the AIR application to the new skin at compilation time
  • Add MXML graphics to the skin to create a scalable application background image
  • Implement an optional skin part that displays the value of the WindowedApplication component’s status property

 

 

Creating a custom skin component for an Adobe AIR application

 

To get started with this tutorial, download and unzip the sample files and then follow these steps to import the starter project into Flash Builder 4:
 
  1. Choose File > Import Flex Project (FXP)
  2. In the Import Flash Builder Project dialog box, browse and select the appskin_starter.fxp file

 

Importing a Flex project in Flash Builder 4.
 
3. Click Finish to import the project.
4. In the Package Explorer view, open the src folder’s default package and open the main application file, PhotoGallery.mxml.

 

The Flash Builder 4 Package Explorer view, opened to the default package.
 
The main application file’s code is very simple; it uses the VerticalLayout class to define its layout and includes instances of the Spark Label and a custom SlideShow component:

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:view="view.*"
title="AIR Photo Gallery"
width="800" height="600">
<s:layout>
    <s:VerticalLayout horizontalAlign="center" paddingTop="80"/>
</s:layout>
<s:Label text="My Photo Gallery" fontSize="24"/>
<view:SlideShow/>
</s:WindowedApplication>

 
5. Choose Run > PhotoGallery to run the application.
 
The application has a very simple appearance, with no custom styles or background graphics. As each photo is displayed, its caption is shown below the photo, and the place where the photo was taken is shown in the status bar at the bottom of the application.
The sample application in its default state, without a custom skin.
 
6. Close the application and return to Flash Builder 4.
 
The application uses a custom component, SlideShow.mxml, that retrieves data from an XML file and displays photos one at a time using a Timer object and Fade effects. Next you’ll explore its code and functionality.
 
  1. Open SlideShow.mxml and its associated ActionScript file, slideShowScript.as, from the project’s view folder.
  2. Explore the code in these two files to see how the custom component loads data from an XML file, cycles through an ArrayList of photo data, displays photos and captions within binding expressions, and changes the application’s status property when a timer event is dispatched from a Timer object.

 

Note: You won’t make any changes to the SlideShow component or its associated ActionScript file in this tutorial. It’s designed as an encapsulated black box component that includes everything it needs to acquire and display data.
 

Creating a custom application skin

 
 
When you create a new Flex 4 desktop application in Flash Builder 4, the main application file uses  as its root element (and therefore as the application’s superclass). You can provide a custom skin for the application by creating a custom component subclassed from the new SparkSkin class. Skin components are typically defined in MXML, with ActionScript code added where required.
 
Follow these steps to create a new custom skin component:
 
1. Return to the main application file, PhotoGallery.mxml.
2. Click Design above the editing area to view the application in Design mode.
3. Right-click on the application background (or Ctrl-click on Mac) and choose Create Skin.
4. In the New MXML Skin dialog box, set the Package to skins.

 

Creating a new custom skin component.
 
5. Set the new components Name to CustomAppSkin.
6. Check the option to Remove ActionScript Styling Code.
7. Click Finish to create the new skin component.
 
The new MXML skin component is a copy of the WindowedApplication component’s default skin, spark.skins.spark.WindowedApplicationSkin. After the initial comments in the code, the start tag for the component’s root element looks like this:
 

<s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:fb="http://ns.adobe.com/flashbuilder/2009"
alpha.disabledGroup="0.5" >

 
The MXML skin component is a subclass of SparkSkin. Notice that in addition to the usual XML namespaces that are added to all MXML applications and components, Flash Builder includes a namespace with an fb prefix.
 
Understanding the [HostComponent] metadata tag
The new skin component is specifically designed for use with the desktop application’s WindowedApplication component. Its [HostComponent] metadata tag defines a link between the component hosting a skin class and the skin class itself. The following declaration is placed in the new MXML skin component just after the starting  tag:
 

<fx:Metadata>
[HostComponent("spark.components.WindowedApplication")]
</fx:Metadata>

 
The [HostComponent] metadata tag makes it possible to bind to any of the component’s property values with the expression hostComponent.[propertyName]. For a Button control, for example, you could use a Label control to output the value of the button’s label property:
 

<s:Label text="{hostComponent.label}"/>

 
Exploring skin states
Spark components can define one or more skin states. Each of these states must be declared within the custom skin component that you’ll use to skin your application. You can find out which skin states are required by a component by looking at its API documentation.
 
1. Open PhotoGallery.mxml in Flash Builder 4 and look at the file in Source view.
2. Click anywhere in the WindowedApplication tag.
3. Press Shift+F2 to open context-sensitive help for the WindowedApplication class.
4. At the top right of the documentation page click Skin States 
 
 
The Skin States link at the top of the documentation page.
 
As shown in FIgure, the WindowedApplication class defines the following required skin states:
  • normal
  • disabled
  • normalAndInactive
  • disabledAndInactive

 

 
The list of required skin states for the WindowedApplication component.
 
Now you’ll review the required skin states in the custom skin component:
1. Open CustomAppSkin.mxml.
2. Below the  tags, locate the  tag set.
3. The MXML skin’s states match the requirements of the WindowedApplication component, and assign some of the states to state groups:
 

<s:states>
    <s:State name="normal" />
    <s:s:State name="disabled" stateGroups="disabledGroup" />
    <s:State name="normalAndInactive" stateGroups="inactiveGroup" />
    <s:State name="disabledAndInactive" stateGroups="disabledGroup, inactiveGroup" />
</s:states>

 
Note: You must define the required skin states even if you don’t use them to modify the appearance of the application. If you forget to define the skin states, you’ll get a runtime error when you run the application.
 
Defining the default content group
The Spark Application and WindowedApplication components define a property named contentGroup, with a required data type of Group. When you declare visual objects in your main application file, they’re automatically added to the contentGroup container as the application starts up. When you use a custom skin component, you must define the group in the skin and assign it the contentGroup id. The component framework then knows where to place the visual objects that are defined in the main application file.
 
1. With CustomAppSkin.mxml still open, delete all of the code after the  element, but be sure to keep the closing "</s:SparkSkin>" tag.
2. Add a Group component with an id of contentGroup. Set its horizontalCenter property to 0 and its topproperty to 170:
 

<s:Group id="contentGroup" horizontalCenter="0" top="170"/>

 
3. Create a new "<s:Label>" tag above the "<s:Group id="contentGroup"…>" tag and set its text property to "My Photo Gallery".
4. Set the Label component’s fontSize to 48, top to 20, horizontalCenter to 0, and fontFamily to Papyrus:
 

<s:Label text="My Photo Gallery" fontSize="48" top="50" horizontalCenter="0" fontFamily="Papyrus"/>

 
Note: I’ve used the Papyrus font because it’s a fancy font that’s available on both Windows and Mac OS X. You can use any font you like.
 
5. Save your changes.
 
 
Attaching the skin to the application
Your Spark skin component now is much simpler than the original skin, but is still compatible with the WindowedApplication component. When you created the new MXML skin component, Flash Builder added code to the application to attach (or bind) the skin to the application during compilation. Follow these steps to see the changes:
 
1. Open PhotoGallery.mxml.
2. Notice that a new skinClass attribute has been added to the starting  <s:WindowedApplication> tag, with its value set to the package and class name of your new custom skin component:
 

skinClass="skins.CustomAppSkin"

 
3. Delete or comment out the application’s  <s:layout> tag set.
4. Delete or comment out the application’s  <s:Label>tag that creates the headline text above the slide show.
 
The application code should now contain only the custom  <view:SlideShow> component:
 

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:view="view.*"
title="AIR Photo Gallery"
width="800" height="600"
skinClass="skins.CustomAppSkin">
<view:SlideShow/>
</s:WindowedApplication>

 
5. Run the application.
At this point, the application looks nearly the same as before, but without the status bar at the bottom of the screen.
6. Close the application and return to Flash Builder 4.
 
The application’s heading label appears above the slide show component, even though it isn’t declared in the main application file. You can follow the same pattern of adding text and graphic elements to the skin to further affect the application’s visual appearance.
 
 
The application with a new custom skin component. The headline label is now part of the custom skin.
 

Drawing vector-based graphics with MXML

 
You can add vector-based graphics to a Flex 4 application with ActionScript classes that are part of the new version of MXML. MXML supports use of the following primitive graphic objects:
 
  • Rect: a rectangle
  • Ellipse: an ellipse
  • Line: a line
  • Path: a filled graphic element that draws a series of segments

 

Each of these is represented in the Flex 4 SDK as an ActionScript class in the spark.primitives package. For example, the following code draws an ellipse that’s 200 pixels wide by 100 pixels high with a red fill color:
 

<s:Ellipse width="200" height="100">
    <s:fill>
        <s:SolidColor color="#FF0000"/>
    </s:fill>
</s:Ellipse>

 
In the preceding code, the Ellipse object’s fill property is set to an instance of the SolidColor class, with its colorattribute set to red using hexadecimal notation. Figure  shows the resulting red ellipse.
 
A red ellipse drawn with MXML code.
 
You’ll first add a background color to the application’s custom skin by drawing a rectangle with a solid color that fills the application’s entire width and height. You’ll then layer another rectangle that creates a frame-like appearance on top of the first.
 
1. Open CustomAppSkin.mxml.
2. Add the following code after the skin states and before the Label control, to draw a rectangle with its width and height set to 100%. The fill is set to a SolidColor object with a color of #d7d5c4:
 

<s:Rect width="100%" height="100%">
    <s:fill>
        <s:SolidColor color="#d7d5c4"/>
    </s:fill>
</s:Rect>

 
Note: The application uses basic layout, similar to Flex 3’s absolute layout. Objects declared first in the MXML code are first in the application’s display list, and therefore are placed in the background. Objects declared later in the code are in the foreground.
 
3. Run the application. Its background should now show the selected color.
4. Close the application and return to Flash Builder 4.
Next, you’ll add another vector graphic that creates a centered background graphic with rounded corners.
5. Add the following code after the first rectangle, and before the Label that displays the application headline:
 

<s:Rect horizontalCenter="0" verticalCenter="0"
width="{this.width-40}" height="{this.height-40}"
radiusX="20" radiusY="20">
<s:fill>
    <s:SolidColor color="#f7f8f5"/>
</s:fill>
</s:Rect>

 
The new rectangle leaves an outer region showing the underlying background color, and has rounded corners.
 
6. Run the application again.
The new nested rectangle with rounded corners should be centered on the screen, displayed behind the slide show component.
7. Close the application and return to Flash Builder 4.
8. Add a filters property to the last rectangle object that implements a drop shadow with an angle of 90 degrees, a color of #333333, and other properties to fine-tune its appearance. The new version of the rectangle code should now look like this:
 

<s:Rect horizontalCenter="0" verticalCenter="0"
width="{this.width-40}" height="{this.height-40}"
radiusX="20" radiusY="20">
    <s:fill>
        <s:SolidColor color="#f7f8f5"/>
    </s:fill>
    <s:filters>
        <s:DropShadowFilter angle="90" color="#333333"
distance="7" alpha="0.65" quality="4"/>
    </s:filters>
</s:Rect>

 
9. Run the application again.
 
As shown in Figure, the nested rectangle will now display a bottom drop shadow.
 
The application with a complete custom skin.
 
Your skin is nearly complete, and the application has a very different appearance than it did previously.
 

Using optional skin parts

 
Spark components such as WindowedApplication can declare optional skin parts. If these skin parts are declared in your custom skin, the host component will already know what to do with them. You can find out which optional skin parts are supported by a component by looking at its documentation.
 
1. Look once more at the documentation for the WindowedApplication class.
Note: You can again use context-sensitive help, as described in the previous section of this tutorial.
2. This time click Skin Parts (not Skin States) at the top right of the documentation page.
 
The WindowedApplication component supports the following skin parts (see Figure):
  • contentGroup:Group
  • controlBarGroup:Group
  • gripper:Button
  • statusBar: IVisualElement
  • statusText: Text
  • BasetitleBar: TitleBar

 

The Skin Parts documentation for the WindowedApplication class.
 
You can implement any of the optional skin parts in your custom skin by declaring an object of the required type and assigning it the id of the skin part as declared in the host component. For example, if you wanted to provide a custom gripper object that the user could click and drag to resize the application, the Button object in the custom skin component might look like this:
 

<s:Button id="gripper"/>

 
Any properties, styles or skins you apply to the Button object would determine its appearance, but the host component would react to the button’s events (such as click, mouseDown and mouseMove) just like it does with its default gripper object.
 
In the following steps, you’ll add a statusText control to the custom application skin. Then, when you set the application’s status property, the statusText control will automatically show the property’s value.
1. Open CustomAppSkin.mxml.
2. At the bottom of the component code, just before the ending </s:SparkSkin> tag, add the following code to create a status bar with a blurred outline, and a status text control with custom font styles:
 

<s:Group id="statusBar" horizontalCenter="0" bottom="50" width="200">
<s:Rect width="100%" height="30">
    <s:fill>
        <s:SolidColor color="#a78d84"/>
    </s:fill>
    <s:filters>
        <s:BlurFilter blurX="20" blurY="20"/>
    </s:filters>
</s:Rect>
<s:Label id="statusText" horizontalCenter="0" verticalCenter="0"
fontFamily="Papyrus" fontWeight="bold" color="#000000" fontSize="18"/>
</s:Group>

 
Notice that the Label control has an id of statusText, matching the id of the WindowedApplication component’s optional skin part.
 
3. Run the application again.
 
Now, each time the photo is updated in the slide show component, the statusText object will show the value of the application’s status property (see Figure).
 
A completed application using the WindowedApplication component’s status property and statusText  skin part.
 
The completed custom skin component code looks like this:
 
<s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:fb="http://ns.adobe.com/flashbuilder/2009" alpha.disabledGroup="0.5" > <fx:Metadata> [HostComponent("spark.components.WindowedApplication")] </fx:Metadata> <s:states> <s:State name="normal" /> <s:State name="disabled" stateGroups="disabledGroup" /> <s:State name="normalAndInactive" stateGroups="inactiveGroup" /> <s:State name="disabledAndInactive" stateGroups="disabledGroup, inactiveGroup" /> </s:states> <s:Rect width="100%" height="100%"> <s:fill> <s:SolidColor color="#d7d5c4"/> </s:fill> </s:Rect> <s:Rect horizontalCenter="0" verticalCenter="0" width="{this.width-40}" height="{this.height-40}" radiusX="20" radiusY="20"> <s:fill> <s:SolidColor color="#f7f8f5"/> </s:fill> <s:filters> <s:DropShadowFilter angle="90" color="#333333" distance="7" alpha="0.65" quality="4"/> </s:filters> </s:Rect> <s:Label text="My Photo Gallery" fontSize="48" top="50" horizontalCenter="0" fontFamily="Papyrus"/> <s:Group id="contentGroup" horizontalCenter="0" top="170"/> <s:Group id="statusBar" horizontalCenter="0" bottom="50" width="200"> <s:Rect width="100%" height="30"> <s:fill> <s:SolidColor color="#a78d84"/> </s:fill> <s:filters> <s:BlurFilter blurX="20" blurY="20"/> </s:filters> </s:Rect> <s:Label id="statusText" horizontalCenter="0" verticalCenter="0" fontFamily="Papyrus" fontWeight="bold" color="#000000" fontSize="18"/> </s:Group> </s:SparkSkin>
 

Where to go from here

In this tutorial you learned how to create and apply a custom skin component for the Flex 4 WindowedApplication component. You can learn more about FXG graphics and custom component skinning from the Flex 4 documentation:
 

 

And be sure to visit the Flex Developer Center for more helpful tips and tutorials.