22 March 2010
A basic understanding of creating applications in Flash Builder and Flex is recommended.
All
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:
status propertyTo 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:
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>
The application has a very simple appearance, with no custom styles or background graphics (see Figure 3). 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 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.
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.
When you create a new Flex 4 desktop application in Flash Builder 4, the main application file uses <s:WindowedApplication> 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:
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.
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 <s:SparkSkin> 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}"/>
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.
WindowedApplication tag.
As shown in Figure 6, the WindowedApplication class defines the following required skin states:
Now you’ll review the required skin states in the custom skin component:
<fx:Script> tags, locate the <s:states> tag set.<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>
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.
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.
<s:states> element, but be sure to keep the closing </s:SparkSkin> tag.id of contentGroup. Set its horizontalCenter property to 0 and its top property to 170:<s:Group id="contentGroup" horizontalCenter="0" top="170"/>
<s:Label> tag above the <s:Group id="contentGroup"…> tag and set its text property to "My Photo Gallery".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.
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:
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"
<s:layout> tag set.<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>
At this point, the application looks nearly the same as before, but without the status bar at the bottom of the screen.
The application’s heading label appears above the slide show component, even though it isn’t declared in the main application file (see Figure 7). You can follow the same pattern of adding text and graphic elements to the skin to further affect the application’s visual appearance.
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 rectangleEllipse: an ellipseLine: a linePath: a filled graphic element that draws a series of segmentsEach 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 color attribute set to red using hexadecimal notation. Figure 8 shows the resulting red ellipse.
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.
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.
Next, you’ll add another vector graphic that creates a centered background graphic with rounded corners.
<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.
The new nested rectangle with rounded corners should be centered on the screen, displayed behind the slide show component.
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>
As shown in Figure 9, the nested rectangle will now display a bottom drop shadow.
Your skin is nearly complete, and the application has a very different appearance than it did previously.
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.
Note: You can again use context-sensitive help, as described in the previous section of this tutorial.
The WindowedApplication component supports the following skin parts (see Figure 10):
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.
</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.
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 11).
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>
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.