Flex 4: Skinning a Button, Spark Style

Some major changes have been implemented with the introduction of Flex 4. The new framework introduces new methods for skinning, states, layouts and declaring non-visual elements in MXML. There's also a new component set called Spark, which will change the way you think about developing modular components. For this article, we will be designing one of the simplest Flex components: a Button. Through this, I'll be implementing some of the major changes so that you can see how it's applied.

Beginning the Button

To start, pop open Flash Builder 4 and create a new Application, making sure you're using the new Flex 4.0 framework.  I named my project SparkButtonDemo.  Once the project has been created, you'll be presented with your Application's MXML file.  You may already notice some differences; Your main Application tag is no longer mx:Application, but s:Application, and there is a new child tag called fx:Declarations.  The simple change in namespace for the Application tag is to indicate that we're no longer using the mx component set, while the fx:Declarations tag is used for any non-visual children (data providers, FileReference objects, services...anything you cannot see).

To start creating our new Button, let's create a new MXML Component called SparkButton.  The component should extend spark.components.Button.

Skinning the Button

The new Spark component set was designed from the ground up to make skinning components easier and more modular.  To start skinning your button, you must create another MXML Component that extends from the spark Skin component (spark.skins.SparkSkin).  Once this class is created, you can start adding some skin elements to it.  The first thing that needs to be added to your skin is a metadata declaration describing the type of component we are skinning.  This looks a little something like this:

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

After adding this code, you will see 4 errors pop up in your Problems window.  Flash Builder is trying to tell you that you haven't defined the required states for a Button.  So let's add 4 states: up, over, down, and disabled.  You should have something that looks like this so far:

<?xml version="1.0" encoding="utf-8"?>
<s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx">
  <fx:Metadata>
    [HostComponent("spark.components.Button")]
  </fx:Metadata>
  <s:states>
    <s:State name="up"/>
    <s:State name="over"/>
    <s:State name="down"/>
    <s:State name="disabled"/>
  </s:states>
</s:SparkSkin>

Next, we will add some graphics to our Button.  For this example we're going to keep it simple, and add a rectangle with a 2 pixel border, and a label control for the button's text.  First, let's add the rectangle:

<s:Rect width="100%" height="100%">
	<s:stroke>
		<s:SolidColorStroke color="0x000000" weight="2"/>
	</s:stroke>
	<s:fill>
		<s:SolidColor color="0xCCCCCC"/>
	</s:fill>
</s:Rect>

Graphics are defined using the new FXG format.  It is similar to SVG, in that it is defined entirely in XML.  This new format is what allows the interchange between Flash Catalyst and Flash Builder 4 (and presumably Flash CS5).

Next, let's add the label control to display the Button's text.  The label must have an id of "labelDisplay" for this to work properly.  This is because the Button classes default skin expects a label control called labelDisplay (http://help.adobe.com/en_US/FlashPlatform//reference/actionscript/3/spark/skins/spark/ButtonSkin.html).  It should be noted that every skinnable component within the Spark framework has a default skin.  To replace this skin, you must implement all of the required properties.  Leaving the label control out, or not naming the label control correctly, does not cause any errors.  You simply won't see the text on the Button.  With that said, here's our label control:

<s:Label id="labelDisplay" width="100%" height="100%" textAlign="center" verticalAlign="middle" fontSize="12"/>

Assigning the label's width and height to 100%, while setting textAlign and verticalAlign both to their center values, will make sure the label is centered within our button.

Viewing the Button

In your Button's MXML code, you must define the skinClass it is going to use.  This looks something like this:

<?xml version="1.0" encoding="utf-8"?>
<s:Button xmlns:fx="http://ns.adobe.com/mxml/2009" 
		  xmlns:s="library://ns.adobe.com/flex/spark" 
		  xmlns:mx="library://ns.adobe.com/flex/mx"
		  skinClass="com.ninem.SparkButtonSkin">
</s:Button>

Place your newly created button on your main application, set the width/height and label properties, and hit go.  Your code should look something like this:

<?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" 
			   xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600" xmlns:ninem="com.ninem.*">
	<ninem:SparkButton width="100" height="50" label="Hello"/>
</s:Application>

You should see your label control in the upper left hand corner of your screen.  It works, but it has no states at the moment.  Let's work on that:

Reacting to Mouse Events

Let's define some simple styling to react to the mouse events a common button expects.  When we roll over, we'll make the text get a little larger.  And when the button's enabled property is set to false, let's make the whole button's alpha property drop to 0.5.

To make the text get a little larger when we rollover, it's as easy as adding one more property to our label in the skin.

<s:Label id="labelDisplay" width="100%" height="100%" textAlign="center" verticalAlign="middle" fontSize="12" fontSize.over="16"/>

You'll see that I added fontSize.over="16."  This will override the fontSize whenever the button is in it's over state.

To set the button's alpha to 0.5 when it's disabled, we add a property to the root of the skin tag.  "alpha.disabled" will set the alpha of the whole button when it enter it's disabled state.

At this point, your skin should look something like this:

<?xml version="1.0" encoding="utf-8"?>
<s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009" 
			 xmlns:s="library://ns.adobe.com/flex/spark" 
			 xmlns:mx="library://ns.adobe.com/flex/mx"
			 minWidth="60" minHeight="20" alpha.disabled="0.5">
	<fx:Metadata>
		[HostComponent("spark.components.Button")]
	</fx:Metadata>
	<s:states>		
		<s:State name="up"/>
		<s:State name="over"/>
		<s:State name="down"/>
		<s:State name="disabled"/>
	</s:states>
	<s:Rect width="100%" height="100%">
		<s:stroke>
			<s:SolidColorStroke color="0x000000" weight="2"/>
		</s:stroke>
		<s:fill>
			<s:SolidColor color="0xCCCCCC"/>
		</s:fill>
	</s:Rect>
	<s:Label id="labelDisplay" width="100%" height="100%" textAlign="center" verticalAlign="middle" fontSize="12" fontSize.over="16"/>
</s:SparkSkin>

So as you can see, skinning has drastically changed in Flex 4.  It may take some time getting used to, but it appears that the changes are for the better.  Your skins are now more modular, and more separated from your "business logic."

To get all of the code associated with this article, point your svn client here: https://code.9mmedia.com/svn/public/SparkButtonDemo/trunk/

14 Comments

14 Responses to “Flex 4: Skinning a Button, Spark Style”


  1. 1 flex developer

    Thanks for sharing knowledge. However, I believe, some day, flex should come up with option like CSS… an external file to manage skinning.

  2. 2 M.E.M

    Thanks so much for this demo!!! My buttons look awesome!!

  3. 3 Lee F.

    It’s been a while since I’ve had to skin Flash components. This is leaps and bounds better than the old Flash Component Framework 2.0 way. Props to Adobe for making this simple and intuitive.

    And props to you for posting this article. Thanks.

  4. 4 Kishore

    Hi thankyou very much, u have explained in a very clear manner !!!

  5. 5 Geo

    Nice post

  6. 6 srikanth g

    hi i need a help i need to change the button color dynamically so please help me out
    button declared as

    public var b:button;

    b.color=”FFOOOOO”;

    is ther any chance of doing this????
    or only we need to skin!!!

  7. 7 Amit Gaur

    Thanks a ton, it helped me a lot
    was really stuck with skin problems but this is very helpful

  8. 8 ash

    great, but how do you integrate this into a workflow with artists using Flash?

    as a dev, i don’t want to be hand editing skin classes all day.

  9. 9 vasu

    Thanks a lot.
    I have one question. How to add text shadow into the button’s text?

  10. 10 lauren

    @vasu,
    You can add a drop shadow directly to any mxml component, including the label in this button.
    See this link for details on how:

    http://livedocs.adobe.com/flex/3/html/help.html?content=styles_11.html

  11. 11 F

    @ flex developer

    The traditional way of skinning components was with CSS in flex 3 and it’s still allowed to be used in flex 4, however this method moves forward in terms of production speed, considering you don’t have to parametrize everything.

  12. 12 worked

    Thanks for posting… my only real concern thus far with Flash Builder 4+ is it’s lack of documentation, examples and tutorials. It’s a fraction in comparison to Java or .NET. Makes working with it difficult at first.

  13. 13 m

    For some reason, the skin isn’t showing up on my button. Your steps are straightforward, but I think something else might be wrong. What could it be? I’m a brand new developer, so any advice would be incredibly helpful.

  14. 14 Meena

    Hello,

    This is an excellent article on skinning.Can you please provide links to any similar articles or code published by you?Please post more samples of skinning a list,datagrid and so on..

    Thanks,
    Meena

  1. 1 Adobe Flash y Actionscript 3 » [Flex 4] En un Botón con estilo: Spark, Pasar texto a componente.

Leave a Reply