Flex Spark Tutorial November 06, 2009

Use css to style a custom spark skin in Flex 4

I’ve finally had a chance to dive in to Flex 4. One trick I learned is incredibly powerful. CSS is a powerful way to specify settings to something from the outside, but it quickly becomes a pain if you need to push pixels around. I’m going to show you how you can create a skin that reads its properties from a stylesheet. This allows css to do what it does best: set simple properties, and lets you do the pixel pushing in the Skin.

Let’s start with some Flex 3 code we’d like to duplicate. This will create a “modal” overlay that covers the app with a translucent screen. You might use this for a LightBox.

<!-- MyOverlay.mxml -->
<mx:Canvas 
    width="100%" height="100%"
    styleName="overlay"
    >

    <!-- Put a panel or something here -->

</mx:Canvas>

/** styles.css **/
.overlay {
    background-color: #000000;
    background-alpha: 0.7;
}

Our First Skin

We want to create this in Flex 4. The (rough) equivalent to canvas is a Group, but it isn’t skinnable, so we can use a SkinnableContainer instead.

<!-- MyOverlay.mxml -->
<s:SkinnableContainer
    width="100%" height="100%"
    skinName="overlay"
    >

    <!-- Stuff -->

</s:SkinnableContainer> 

SkinnableContainer doesn’t have a way to set backgroundColor or backgroundAlpha! The css will not work.

Let’s create the same functionality in a skin instead.

<!-- skins/OverlaySkin.mxml -->
<s:SparkSkin ... >

    <!-- The highest-level base class that can use this-->
    <fx:Metadata>
        [HostComponent("spark.components.SkinnableContainer")]
    </fx:Metadata>
    
    <!-- specify all the states the host component uses -->
    <s:states>
        <s:State name="normal"/>
        <s:State name="disabled"/>
    </s:states>
    
    <!-- Here's our overlay! -->
    <s:Rect left="0" right="0" top="0" bottom="0">
        <s:fill>
            <s:SolidColor color="#000000" alpha="0.7"/>
        </s:fill>
    </s:Rect>
    
    <!-- Put the panel, or whatever is in the component here --> 
    <s:Group id="contentGroup" verticalCenter="0" horizontalCenter="0">
        <s:layout><s:BasicLayout/></s:layout>
    </s:Group>
    
</s:SparkSkin> 

That’s not too bad. We have a skin, and now we can apply it to our component by setting the skinClass property. For example:

<!-- MyOverlay.mxml -->
<s:SkinnableContainer
    width="100%" height="100%"
    skinClass="skins.OverlaySkin"
    >

    <!-- content -->

</s:SkinnableContainer>

Or we can set the skinClass in the style.

<!-- MyOverlay.mxml -->
<s:SkinnableContainer
    width="100%" height="100%"
    styleName="overlay" 
    >

    <!-- content -->

</s:SkinnableContainer>

/** styles.css **/
.overlay {
    skinClass: ClassReference("skins.OverlaySkin");
}

Using CSS on the Skin

Now we have a styleName we can apply to any SkinnableContainer and it will make it look like our black, translucent overlay. This works great, so we start using it, but pretty soon we realize that we need to be able to add a background to another container, but we don’t want to create a new skin just to tweak the color and alpha. Here is where it gets fun. We change the Rect tag in our skin to look like this:

<s:Rect left="0" right="0" top="0" bottom="0">
	<s:fill>
		<s:SolidColor color="{getStyle('backgroundColor')}" alpha="{getStyle('backgroundAlpha')}"/>
	</s:fill>
</s:Rect>

Now it will get it’s color and alpha from the style. We can change our overlay style to look like this

/** styles.css **/
.overlay {
    background-color: #000000;
    background-alpha: 0.7;
    skinClass: ClassReference("skins.OverlaySkin");
}

That looks a lot more like the Flex 3 version! We can then add more styles for other kinds of containers that need backgrounds, and our skin is now much more useful than before.

The Final Version

<!-- skins/BackgroundSkin.mxml -->
<?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/halo">
    
    <fx:Metadata>
        [HostComponent("spark.components.SkinnableContainer")]
    </fx:Metadata>
    
    
    <s:states>
        <s:State name="normal"/>
        <s:State name="disabled"/>
    </s:states>
    
    <s:Rect left="0" right="0" top="0" bottom="0">
        <s:fill>
            <s:SolidColor color="{getStyle('backgroundColor')}" alpha="{getStyle('backgroundAlpha')}"/>
        </s:fill>
    </s:Rect>
    
    <!-- Tells the skin where to put the children you have specified -->
    <s:Group id="contentGroup" verticalCenter="0" horizontalCenter="0">
        <s:layout><s:BasicLayout/></s:layout>
    </s:Group>
    
</s:SparkSkin>

/** styles.css **/
.overlay {
    background-color: #000000;
    background-alpha: 0.7;
    skinClass: ClassReference("skins.OverlaySkin");
}

.error {
    background-color: #FF0000;
    background-alpha: 1.0;
}

.success {
    background-color: #00FF00;
    background-alpha: 1.0;
}

Using this technique will allow you to play to the strengths of both CSS and Spark Skins.

August 26, 2009

FlashLib Library Index Features

In An Army of Small Libraries I suggested creating a site that indexes every known bit of reusable Actionscript code in existence. FlashLib.org is up, and I’d like to solicit feedback on the planned features as it progresses. Please look over these and let me know what you think.

Read the rest »

August 20, 2009

An Army of Small Libraries

Ted Patrick, known on twitter as @adobeted, recently released two interesting as3 libraries: FDOT and Tubes. This is not unique to Ted. People constantly develop amazing solutions to common problems. The problem is that it is hard to find these solutions. Unless the developer already has a large following, his code usually dies in obscurity. Someone facing a common problem will either develop their own solution, or find a stale solution on google. Ted has been proposing that someone create a standard as3 library. I would like to recommend an alternative.

Read the rest »

August 11, 2009

Client-Side Flex Logging with Shared Object

Having your app keep a detailed log can be indispensable for figuring out tricky user-reported bugs. This is easy on the server-side, where you can use any logging framework or just write to a file. Flash includes the trace function, which is useful while developing, but nearly impossible to get from an end-user. Flex, however, has a good logging api that lets you put log statements anywhere you want. I’ve always wanted the interface to be as easy as trace, so I write a couple of scripts to make it easier.

Read the rest »

August 03, 2009

How to write your own PHP templating engine

MVC is all the rage. Choosing a framework, however, is not so easy. The view part of a standard php MVC framework usually involves grabbing one or more model objects and printing out some text (html) about them. There are several frameworks that do this, including the famous smarty. There are even more frameworks, like Zend and CakePHP that include templating as a subset of what they do.

Read the rest »

August 03, 2009

Easy Daemons in PHP

This class and script makes it easy to turn a one-shot php script into a daemon that runs in the background on a timer. This is good for things you want to happen infrequently. For example, your site may need to use curl to fetch several different rss feeds, combining them into one feed. You don’t want to fetch all the feeds every time someone asks for the combined one. It is better to generate the combined feed every 5 minutes or so.

Read the rest »

July 31, 2009

Create a Blog in Ruby and Sinatra - Part 2 - Models

This is part 2 of my Sinatra blog tutorial. Today I’m talking about the database layer. Don’t forget to check out the full source of my blog on github.

Read the rest »

July 30, 2009

Page Stack - Navigate by Page Name

Building a navigation system in Flex is harder than it should be. Trying to figure out how to decouple your navigation model from the view is unintuitive. ViewStack is the obvious choice for it, but it leaves you with only two options, neither of which is good.

Read the rest »

July 29, 2009

Custom Block Helper in ERB

Something I learned how to do in rails, but had a hard time replicating without it, is create a custom helper that accepts a block. I figured out how to write to the screen from the helper. @_out_buf is the name of the variable I needed.

Read the rest »

July 28, 2009

A New Home

My blog has been going through a state of flux lately. I hadn’t posted in a couple of months, and when I discovered posterous, I thought I had found the perfect system. Well, it didn’t make me post any more than I used to - it just made my blog look worse.

Read the rest »

Show All Posts