Did you know? DZone has great portals for Python, Cloud, NoSQL, and HTML5!

Introducing skinning in Flex 4 beta 2

February 08, 2010 AT 2:01 PM
  • submit to reddit

One of the main themes for the Flex 4 (codename: Gumbo) release is "Design in Mind", and skinning is a big part of that theme. Flash Player is the delivery mechanism for some of the most creative work to be found on the web today. However, Flex applications have gained a reputation for looking too similar to each other, as many developers choose to use the Flex default look and feel (known as Halo) as opposed to applying extensive styling or skinning.

Flex 4 beta makes it easier to completely change the look and feel of an application. The new skinning architecture builds on top of other changes in Flex 4 and provides a clean separation between the logic and visual elements of a component. Because of this, none of the components in Flex 4 beta contains any information about their visual appearance. All of that information is contained in the skin file, and thanks to FXG and the new states syntax, the new skin files can be completely written in MXML, making them easier to read and write, as well as easier to access with tools.

In this article, you'll learn about the improvements to the skinning architecture in Flex 4 beta. By writing a basic skin for a button, you'll learn a little bit about FXG and the new states syntax. Next, you'll learn about the contract a component and a skin use to interact with each other through the process of skinning a slider. Lastly, you'll delve into skinnable components as you create a new component ripe for skinning.

Note: Throughout this document, the term Halo components refers to components originally included in Flex 3. The term Spark components refers to the new set of components in Flex 4 beta.

Requirements

In order to make the most of this article, you need the following software and files:

Flex 4 beta
Sample files:
Prerequisite knowledge

This article assumes knowledge of the Flex 3 Framework.

Writing a simple button skin

FXG is a declarative markup language for vector graphics built to take advantage of Flash Player. With the new markup, it is easy to create a custom button. For this button, start with a simple rectangle with text inside of it (see Figure 1).

Sample1.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark">
<s:Group verticalCenter="0" horizontalCenter="0">
<s:Rect id="rect" radiusX="4" radiusY="4" top="0"
right="0" bottom="0" left="0">
<s:fill>
<s:SolidColor color="0x77CC22" />
</s:fill>
<s:stroke>
<s:SolidColorStroke color="0x131313" weight="2"/>
</s:stroke>
</s:Rect>

<s:Label text="Button!" color="0x131313"
textAlign="center" verticalAlign="middle"
horizontalCenter="0" verticalCenter="1"
left="12" right="12" top="6" bottom="6"
/>
</s:Group>
</s:Application>

The sample1 button

Figure 1. The sample1 button

If you're familiar with Flex 3, you'll be familiar with the syntax above, though you might not be familiar with the specific components used. The Group container is the basic, chromeless container in Spark. Rect is a new FXG graphic primitive, and it's what you'd expect—a rectangle. The last component in the document, Label, is a new text component in Spark. The MXML reads just like a description of the component—it's a rectangle with rounded corners that has a 1-pixel dark-gray stroke and a green fill with some text in the center.

One of the great things about FXG is that not only is it much easier to understand than programmatic drawing instructions, it is also much more toolable because of the structure of XML. For more info about FXG, see the FXG specification.

Converting your Button graphic to a Button skin

So far, the MXML document is just static artwork with no interactivity. It doesn't yet take advantage of the new skinning features in Flex 4 beta. For that, you need to hook it up to the Button component and use it as a skin. To create a skin file for Spark, create a new MXML file with Skin as the root tag. Then, copy in the graphics code from above:

ButtonSkin1.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" alpha.disabled=".5">

<!-- states -->
<s:states>
<s:State name="up" />
<s:State name="over" />
<s:State name="down" />
<s:State name="disabled" />
</s:states>

<!-- border and fill -->
<s:Rect id="rect" radiusX="4" radiusY="4" top="0" right="0" bottom="0" left="0">
<s:fill>
<s:SolidColor color="0x77CC22" />
</s:fill>
<s:stroke>
<s:SolidColorStroke color="0x131313" weight="2"/>
</s:stroke>
</s:Rect>

<!-- text -->
<s:Label text="Button!" color="0x131313"
textAlign="center" verticalAlign="middle"
horizontalCenter="0" verticalCenter="1"
left="12" right="12" top="6" bottom="6"
/>
</s:Skin>

You'll notice there is one more addition in the file states. I will discuss them a little later.

With your skin file complete, you need to associate it with a Button component. Every skinnable component in the Spark architecture is associated with a skin via the skinClass CSS style that can be set either through style sheets or inline via MXML. In this case, I'll use the latter:

Sample2.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark">
<s:Button verticalCenter="0" horizontalCenter="0" skinClass="ButtonSkin1"
click="trace('I\'ve been clicked!')" focusIn="trace('focus...on me?')" />
</s:Application>

The sample2 button

Figure 2. The sample2 button

You've now hooked up the button to a new skin file. The Button component contains all the behavioral logic for the button. It adds the event listeners, dispatches new events, figures out what state the component is in, and so on. The skin doesn't have to deal with any of that and just defines the visuals of the component.

However, the Button doesn't look any different than the static graphic you first created. The button is interactive, but it doesn't appear that way. This is because you haven't yet defined how the button looks in different states.

 

Introducing the skinning contract

A static skin is pretty boring. For something interesting, the skin must be able to interact with the component and vice versa. These two elements interact with each other through the skinning contract. There are three pieces to this: skin states, data, and parts (see Figure 3). On one side, the component defines these three different pieces, and on the other side, the skin reacts to them.

The skinning contract comprises data, parts, and states.

Figure 3. The skinning contract comprises data, parts, and states.

Defining skin states

Each skinnable component in Spark has a set of skin states. You can change the appearance of your skin based on what skin state the component is in. For a Button, there are four basic skin states: up, over, down, and disabled. You can modify the skin to have a different appearance in each of these states (see Figure 4).

ButtonSkin2.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" alpha.disabled=".5">

<!-- states -->
<s:states>
<s:State name="up" />
<s:State name="over" />
<s:State name="down" />
<s:State name="disabled" />
</s:states>

<!-- dropshadow for the down state only -->
<s:Rect radiusX="4" radiusY="4" top="0" right="0" bottom="0"
left="0" includeIn="down">
<s:fill>
<s:SolidColor color="0"/>
</s:fill>
<s:filters>
<s:DropShadowFilter knockout="true" blurX="5" blurY="5"
alpha="0.32" distance="2" />
</s:filters>
</s:Rect>

<!-- border and fill -->
<s:Rect id="rect" radiusX="4" radiusY="4" top="0" right="0"
bottom="0" left="0">
<s:fill>
<s:SolidColor color="0x77CC22" color.over="0x92D64E"
color.down="0x67A41D"/>
</s:fill>
<s:stroke>
<s:SolidColorStroke color="0x131313" weight="2"/>
</s:stroke>
</s:Rect>

<!-- highlight on top -->
<s:Rect radiusX="4" radiusY="4" top="2" right="2" left="2"
height="50%">
<s:fill>
<s:LinearGradient rotation="90">
<s:GradientEntry color="0xFFFFFF" alpha=".5"/>
<s:GradientEntry color="0xFFFFFF" alpha=".1"/>
</s:LinearGradient>
</s:fill>
</s:Rect>

<!-- text -->
<s:Label text="Button!" color="0x131313"
textAlign="center"
verticalAlign="middle"
horizontalCenter="0" verticalCenter="1"
left="12" right="12" top="6" bottom="6"
/>
</s:Skin>
ButtonSkin2.mxml

The four skin states of the Button

Figure 4. The four skin states of the Button

Based on what skin state it is in, the component looks different because of how you've defined the skin. This skin file is taking advantage of the new dot syntax for states. This is a new feature in Flex 4 beta, which makes writing state modifications much more clear and concise. The syntax is property.stateName="value of that property in that state". For example, alpha.disabled=".5" means that when the button goes into the disabled skin state, the skin will change the alpha to 50%. In the over and down states, I've defined a different fill color with color.over="0x92D64E" color.down="0x67A41D".

With the new state syntax, there's an includeIn and excludeFrom property on every MXML component. The drop shadow in the button skin is only included in the down state, which gives it a nice pressed look. Also, to jazz up the skin, I've added another rectangle to highlight the top of the button in all states.

Note: For more info on the enhanced state syntax in Flex 4, check out the new states syntax specification.

Playing around with the button is an interactive experience as the button changes its visual appearance based on its skin state. One thing you will notice, though, is that the component's text is hard-coded to "Button!". In the next section, you'll see how to hook up the skin to display the component's data, in this case, the Button's label property.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)