Beginner’s Guide to Skinning your Flex 4 Application or AIR Application

While working on the Tour de Flex samples for Flex 4, I spent some time digging into the new Flex 4 Skinning Architecture and found that I could do some really cool stuff with it. Though I’m definitely NOT a designer, I was impressed by the level of control it offered me and wanted to share some basics/tips for skinning your Flex/AIR applications.

So you want to skin your app… where do you start?

1) Copy the source code for the default ApplicationSkin.mxml or WindowedApplicationSkin.mxml file from the Flex 4 SDK source into a new MXML component file within your project. The path should be something like: /<your-flex4-sdk-folder>/frameworks/projects/spark/src/spark/skins/spark/ (or on Windows it would be c:\..\<your-flex4-sdk-folder>\frameworks\projects\spark\src\spark\skins\spark\). You can also use the default skins specified in the Wireframe Flex 4 theme included in the SDK. They are sometimes simpler to work with (for more info on Flex 4 themes, see this link). The path to the wireframe skins will be something like: /<your-flex4-sdk-folder>/frameworks/projects/wireframe/src/spark/skins/wireframe/ (or on Windows it would be c:\..\<your-flex4-sdk-folder>\frameworks\projects\wireframe\src\spark\skins\wireframe\)

I figure what better way to make sure you have control over every detail than by starting with the Flex 4 SDK default skin class currently being used by the container or component. Many times you will not need that level of control and can omit parts of the code that are not changing, however I personally found it nice to see the options I had for modifying skin parts and the fact that they included comments in their skins to explain what each part is.

This is a quick and easy way to understand specifically which skin parts are defined as well. You can also check the Adobe Flex 4 Livedocs for that particular host component’s class documentation to see the required skin parts, skin states etc. Generally though I begin by just grabbing the skin source for the host component I want to skin and modifying or omitting different parts to see how it affected the component (so in the case of skinning an app I would look for either spark.components.ApplicationSkin.mxml or spark.components.WindowedApplication.mxml respectively).

Note: ‘host component’ simply refers to the Spark component/container I want to skin.

2) Change the parts you want to control. So for an Application you may want to modify the ApplicationControlBar look in addition to the background. This can all be done by modifying the source code for the ApplicationSkin.mxml class. Just rename it and modify it to your liking. These examples do not go into skinning the ApplicationControlBar, but you can apply the information from this post in doing so.

Quick Tip: if you just want to use a graphic for your application background, you could use a skin as simple as this:

01<?xml version="1.0" encoding="utf-8"?>
02<s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009"
05 
06    <fx:Metadata>
07        [HostComponent("spark.components.Application")]
08    </fx:Metadata>
09 
10    <s:states>
11        <s:State name="normal" />
12        <s:State name="disabled" />
13    </s:states>
14 
15    <s:BitmapImage width="400" height="500" source="@Embed('assets/SampleBackground.png')"/>
16    <s:Group id="contentGroup" left="0" right="0" top="0" bottom="0">
17</s:SparkSkin>

Note: You must keep the ‘contentGroup’ part in your custom skin so the content of your application shows, otherwise you will only see your image. In the case of skinning an Application, the actual Application.mxml Livedocs will show you which skin parts are required. Scroll down until you see the section labeledSkin Parts in the class documentation. You can also view the inherited skin parts and skin states there.

If you want your image to actually fill in the entire space of the app, then you could use something like this:

01<?xml version="1.0" encoding="utf-8"?>
02<s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009"
05 
06 <fx:Metadata>
07     [HostComponent("spark.components.Application")]
08 </fx:Metadata>
09 
10 <s:states>
11     <s:State name="normal" />
12     <s:State name="disabled" />
13 </s:states>
14 
15 <s:Rect id="backgroundRect" left="0" right="0" top="0" bottom="0">
16     <s:fill>
17         <s:BitmapFill source="@Embed('assets/SampleBackground.png')"/>
18     </s:fill>
19 </s:Rect>
20 
21 <s:Group id="contentGroup" left="0" right="0" top="0" bottom="0" />
22</s:SparkSkin>

3) Apply the custom skin to your MXML application. You can do this in two ways, either inline MXML or CSS. For inline MXML, you simply set the skinClass property on the root Application tag to the fully-qualified name of your custom class. For instance:

3   skinClass="skins.CustomApplicationSkin">

In CSS it would be something like:

1s|Application
2{
3    skinClass: ClassReference("com.devgirl.blogexample.skins.CustomApplicationSkin");
4}

I generally use the skinClass property for application skins. The CSS way to do it is nice when you want to apply a certain skin to all instances of a component that you may have created a custom class for, such as Button for example.

Below are a couple of examples of skinning an application with a simple custom application skin (keeping in mind the fact that I am so NOT a designer ;) ) but, they should help give an idea of what you are able to do. The screenshot is shown first followed by the source code for the custom skin and Flex app:

Picture 5

The custom background skin for the above screenshot looks like:

01<?xml version="1.0" encoding="utf-8"?>
02<!-- ../skins/BackgroundImageAppSkin.mxml>
03<s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009"
04        xmlns:mx="library://ns.adobe.com/flex/halo"
05        xmlns:s="library://ns.adobe.com/flex/spark">
06 
07    <fx:Metadata>
08        [HostComponent("spark.components.Application")]
09    </fx:Metadata>
10 
11    <s:states>
12        <s:State name="normal" />
13        <s:State name="disabled" />
14    </s:states>
15 
16    <!-- This image fill also specifies padding around it -->
17    <s:Rect id="backgroundRect" left="100" right="100" top="20" bottom="20">
18        <s:fill>
19            <s:BitmapFill source="@Embed('assets/wood-bg.png')"/>
20        </s:fill>
21    </s:Rect>
22 
23    <s:Group id="contentGroup" left="0" right="0" top="0" bottom="0" />
24</s:SparkSkin>

The Flex application code for this screenshot is the following:

01<?xml version="1.0" encoding="utf-8"?>
02<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
03               xmlns:s="library://ns.adobe.com/flex/spark"
04               xmlns:mx="library://ns.adobe.com/flex/halo"
05               skinClass="skins.BackgroundImageAppSkin"
06               backgroundColor="0x000000">
07 
08    <fx:Declarations/>
09 
10    <s:VGroup horizontalCenter="0" verticalCenter="0">
11        <s:Label text="Wood Sales Int'l" fontSize="42" />
12        <s:Border borderColor="0x000000" borderWeight="3" cornerRadius="7" horizontalCenter="0" verticalCenter="0">
13            <s:VGroup>
14                <mx:Form fontSize="16">
15                    <mx:FormItem label="Userid:">
16                        <s:TextInput id="userid"/>
17                    </mx:FormItem>
18                    <mx:FormItem label="Password:">
19                        <s:TextInput id="pw"/>
20                    </mx:FormItem>
21                    <mx:FormItem>
22                        <s:Button label="Login"/>
23                    </mx:FormItem>
24                </mx:Form>
25            </s:VGroup>
26        </s:Border>
27    </s:VGroup>
28</s:Application>

Now I can change just one line in my sample code, the skinClass property to a different skin, and produce this:

Picture 7

And below is the custom gradient background skin for the above screenshot:

01<?xml version="1.0" encoding="utf-8"?>
02<s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009"
03        xmlns:mx="library://ns.adobe.com/flex/halo"
04        xmlns:s="library://ns.adobe.com/flex/spark">
05 
06    <fx:Metadata>
07        [HostComponent("spark.components.Application")]
08    </fx:Metadata>
09 
10    <s:states>
11        <s:State name="normal" />
12        <s:State name="disabled" />
13    </s:states>
14 
15    <!-- border -->
16    <s:Rect left="10" right="10" top="10" bottom="10" radiusX="9" radiusY="9">
17        <s:stroke>
18            <mx:SolidColorStroke color="0xCCCCCC" alpha=".5" weight="4"/>
19        </s:stroke>
20    </s:Rect>
21 
22    <s:Rect id="backgroundRect" left="10" right="10" top="10" bottom="10" radiusX="9" radiusY="9">
23        <s:fill>
24            <s:LinearGradient rotation="90">
25                <s:entries>
26                    <s:GradientEntry color="0x0000FF" ratio="0.00" alpha="0.8"/>
27                    <s:GradientEntry color="0x336699" ratio="1.0" alpha="0.5"/>
28                    <s:GradientEntry color="0xCCCCCC" ratio="0.5" alpha="0.8"/>
29                </s:entries>
30            </s:LinearGradient>
31        </s:fill>
32    </s:Rect>
33 
34    <s:Group id="contentGroup" left="0" right="0" top="0" bottom="0" />
35</s:SparkSkin>

Again, the sample Flex application MXML looks exactly the same except we are specifying my custom gradient background skin on the skinClass property:

01<?xml version="1.0" encoding="utf-8"?>
02<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
03               xmlns:s="library://ns.adobe.com/flex/spark"
04               xmlns:mx="library://ns.adobe.com/flex/halo"
05               skinClass="skins.GradientBackgroundAppSkin">
06 
07    <fx:Declarations/>
08 
09    <s:VGroup horizontalCenter="0" verticalCenter="0">
10        <s:Label text="Wood Sales Int'l" fontSize="42" />
11        <s:Border borderColor="0x000000" borderWeight="3" cornerRadius="7" horizontalCenter="0" verticalCenter="0">
12            <s:VGroup>
13                <mx:Form fontSize="16">
14                    <mx:FormItem label="Userid:">
15                        <s:TextInput id="userid"/>
16                    </mx:FormItem>
17                    <mx:FormItem label="Password:">
18                        <s:TextInput id="pw"/>
19                    </mx:FormItem>
20                    <mx:FormItem>
21                        <s:Button label="Login"/>
22                    </mx:FormItem>
23                </mx:Form>
24            </s:VGroup>
25        </s:Border>
26    </s:VGroup>
27</s:Application>

So you can see just how quickly you can make your application theme look entirely different with just a one line change and not modifying any behavioral logic. It’s very powerful and there are so many more things beyond this that you can do with the FXG drawing API’s.

A couple other tips for non-designer folks out there… You can use the Adobe CS4 products such as Photoshop, Illustrator and Fireworks etc to create your skins and then export them as FXG and use them within your skins. You do not have to understand all of the FXG classes and properties necessarily but can just visually draw what you want with those products and either do a ‘Save As’ .fxg extension type (such as in Photoshop), or use the Export to FXG command (from the Commands menu) in Fireworks. For instance, it may generate your FXG for a drawn border (using the Path FXG object) based on what you drew that you can use without having to figure all the specific points out. You can then extract the parts you want from the FXG and place them in your custom skin class. Many times you will also get an image as a result and will use that within your skin class as well, like I did in the wood sample above. The image is exported and referenced as part of the FXG from the CS4 tools. If you play around with it a bit and export the FXG to see what it created, you will quickly see what you can do.

Important to note: One FXG-related issue I ran into when exporting from Photoshop or Fireworks, is that there are times when what you produced will result in either a TextGraphic or BitmapGraphic in the FXG source and you must manually change them to RichText (for TextGraphic) and BitmapImage (for BitmapGraphic) or you will get compiler issues with the namespace. Detailed information about this can be found here.

Also, an obvious tip to most, but just in case it helps someone… When I create my new image, I always use the ‘Transparent’ background mode so that it fits in with whatever color scheme I might choose within the app. If you know exactly what color you are using already, you can set the background to that and it will matte it to that color. This is probably already known to many, but for those that might not know, it will save you time figuring out why there is a white border around your image in your app!

Also note, everything above can be applied to skinning your AIR applications as well. You simply start with the WindowedApplicationSkin.mxml default skin class from the Flex 4 SDK.

There’s so much to the skinning architecture to understand, that you should definitely check out the Flex 4 team blogs and Livedocs Help to complete your knowledge.

posted @ 2010-03-30 16:00  fxair  阅读(220)  评论(0)    收藏  举报