Saturnboy
 7.15

Back in the days of Flex 3, if you wanted multiple content areas in your main application, you’d need to arrange some set of containers (Canvas, HBox, VBox) in the app and fill them with content. It was just your basic Flex 3 development process. The danger, of course, is that you are mixing content with presentation, aka bad separation of concerns. Today, with the power of Flex 4 skins, we can avoid this issue by moving the presentation layer into a skin (or set of skins). And thus, we can do a much better job achieving a happy level of separation of concerns.

The Flex 3 Way

To give a concrete example, I’ll build a blog layout (yes, another blog layout) with a header, footer, sidebar, and main content areas. But before we get started, let’s review the old Flex 3 way:

<mx:HBox id="header">
    <mx:Image source="@Embed('assets/logo.png')" />
</mx:HBox>
 
<mx:Canvas id="body" width="800">
    <mx:Text text="main content" width="600" />
 
    <mx:VBox id="sidebar" x="600" width="200">
        <mx:Text text="Sidebar" />
        <mx:Text text="sidebar content" width="100%" />
    </mx:VBox>
</mx:Canvas>
 
<mx:VBox id="footer">
    <mx:Text text="2010 saturnboy" styleName="footer" />
</mx:VBox>

The above code comes from a previous post, Designing in Flex 3, but has been modified to make sense here. You’ve got you basic blog design: a box for the header, footer, and body, where body is subsequently is divided into a main content area and a sidebar.

The 3-in-4 Way, aka The Wrong Way

The unfortunate next step in a Flex developer’s evolution is what I like to call the Flex 3-in-4 way. This is a the way of neanderthals, which is to say, it is an evolutionary dead end. If you ever have the bad luck to see 3-in-4 code, you can be sure you are dealing with a novice Flex 4 developer. In general, the 3-in-4 way consists of making the simple transcription: CanvasGroup, HBoxHGroup, VBoxVGroup. But the most damning tipoff of a 3-in-4 developer is the assertion that one is now a Flex 4 developer and the learning curve wasn’t all that bad. While I do think Flex 4 is more of an evolutionary release than a revolutionary release, it’s different enough. And it is particularly different on the design side of the framework, how it handles skins, layout, etc.

If we just transcribe the above example, we get some classic 3-in-4 code:

<s:HGroup id="header">
    <s:Label text="Multi Content Area Example" styleName="header" />
</s:HGroup>
 
<s:Group id="body" width="800">
    <s:Label text="main content" width="600" />
 
    <s:VGroup x="600" width="200" styleName="sidebarBox">
        <s:Label text="Sidebar" styleName="title" />
        <s:Label text="sidebar content" styleName="sidebar" />
    </s:VGroup>
</s:Group>
 
<s:VGroup id="footer">
    <s:Label text="2010 saturnboy" styleName="footer" />
</s:VGroup>

*Barf*, please not do this. This code has all the same issues as the Flex 3 code in the first example, and moreover it is a slap in the face of The Flex 4 Way and all of its improvements.

The Flex 4 Way

Yes, there is a Flex 4 Way and it looks like this.

First, we rewrite the main app using a custom container. Ignoring the specifics of the custom container for a moment, here is the re-written main app (minus some clutter):

<containers:headerContent>
    <s:Label text="Multi Content Area Example" styleName="header" />
</containers:headerContent>
 
<containers:sidebarContent>
    <s:RichText left="0" right="0" styleName="sidebar">
        <s:content>
            <s:p fontSize="20">Sidebar</s:p>
            <s:p>sidebar content</s:p>
        </s:content>
    </s:RichText>
</containers:sidebarContent>
 
<containers:footerContent>
    <s:Label text="2010 saturnboy" styleName="footer" />
</containers:footerContent>
 
<s:RichText left="0" right="0">
    <s:content>
        <s:p fontSize="30">Content</s:p>
        <s:p>main content</s:p>
    </s:content>
</s:RichText>

As you can see, the main app is now a nice set of semantic buckets, one for each of the content areas. Header stuff goes in the headerContent bucket, footer stuff goes in the footerContent bucket, etc.

Building a Multi Content Area Container

Second, we need to create a custom container with the nice set of semantic buckets used in the above code. This is achieved by following a straightforward formula:

  1. Extend SkinnableContainer – Extend SkinnableContainer or some child class. In our sample app, our custom container extends Application (which extends SkinnableContainer).
  2. Add Buckets – add some content buckets (in the form of xxxContent) as Arrays. These become the MXML tags used to bucket components together. Each content bucket has a public getter, but most importantly a public setter that accepts an incoming Array of IVisualElements and uses the magical mxmlContent property to assign it to the associated SkinPart.
  3. Add SkinParts – add some matching SkinParts (in the form of xxxGroup) as spark Groups. There are used in the custom skin to display the content. Also, I usually set required="false" to make everything optional.
  4. Add partAdded() & partRemoved() – override the new Flex 4 skinning lifecycle methods to wire the incoming content to the outgoing SkinPart.

The custom component code is actually easier to follow then the description. Here is a custom container with only one additional content bucket, sidebarContent, and its matching SkinPart, sidebarGroup:

package containers {
    import spark.components.Group;
    import spark.components.Application;
 
    public class MainApp extends Application {
        [SkinPart(required="false")]
        public var sidebarGroup:Group;
 
        private var _sidebarContent:Array = [];
 
        public function MainApp() {
            super();
        }
 
        [ArrayElementType("mx.core.IVisualElement")]
        public function get sidebarContent():Array {
            return _sidebarContent;
        }
        public function set sidebarContent(value:Array):void {
            _sidebarContent = value;
            if (sidebarGroup) {
                sidebarGroup.mxmlContent = value;
            }
        }
 
        override protected function partAdded(partName:String, instance:Object):void {
            super.partAdded(partName, instance);
 
            if (instance == sidebarGroup) {
                sidebarGroup.mxmlContent = _sidebarContent;
            }
        }
 
        override protected function partRemoved(partName:String, instance:Object):void {
            super.partRemoved(partName, instance);
 
            if (instance == sidebarGroup) {
                sidebarGroup.mxmlContent = null;
            }
        }
    }
}

Following the four steps: we extend Application, have a sidebarContent bucket and its associated sidebarGroup SkinPart, and override partAdded() and partRemoved() to wire everything together.

Skinning a Multi Content Area Container

Skinning in Flex 4 is awesome, and like everyone says, it’s easily one of the best new features in the framework. While I find the skinning process fairly straightforward, I would never call it trivial, mostly due to the depth and flexibility of the skinning system.

We need a custom skin for our custom multi content area component. This is probably the 10% case for skinning, but it’s also the coolest. In my experience, an average Flex 4 app has many Button skins (like 10 or even 20), a few default component skins (skins for List, DropDownList, TextInput, etc.), and maybe only two or three skins for custom components.

The skin itself is nothing special. To display our custom component’s SkinParts, we simply include a Group with the matching id attribute. For example, our skin will include a <s:Group id="sidebarGroup" /> to display the sidebarGroup SkinPart. Just rinse, wash, repeat, to add all of our custom content areas in the container to the skin.

Here is a trivial skin:

<s:Skin ... >
    <fx:Metadata>
        [HostComponent("containers.MainApp")]
    </fx:Metadata> 
 
    <s:states>
        <s:State name="normal" />
        <s:State name="disabled" />
    </s:states>
 
    <s:VGroup left="40" right="40" top="40" bottom="40" gap="20">
        <s:Group id="headerGroup" width="100%" />
        <s:Group id="contentGroup" width="100%" />
        <s:Group id="sidebarGroup" width="100%" />
        <s:Group id="footerGroup" width="100%" />
    </s:VGroup>
</s:Skin>

In this trivial skin, we just shove all the content groups (including SkinnableContainer‘s default Group, contentGroup) into a VGroup. Also note, we correctly set HostComponent to our custom container. If you are thinking, "Hey, this skin looks similar to the Flex 3 and 3-in-4 example code, just minus the content" that’s exactly the point.

Lastly, we wire out skin to our custom component via CSS:

containers|MainApp {
    skinClass:ClassReference('skins.TrivialAppSkin');
}

Using skinClass to wire a skin to a component is so 2009. The sample app has its CSS inline, but in any real app I’ll always put this in an external file.

Conclusion

After this, there’s really not much more to say. You can certainly create a more complicated arrangement of the multiple content areas by making a more complicated skin. I’ve done exactly this in the final sample, which includes three different skins and a skin switcher (click 1, 2, or 3 to switch skins).

» view MultiConentArea sample (view source enabled)

Files

 5.10

Photoshop does this annoying thing where purely vertical gradients have some horizontal variation. Yes, it’s usually only plus or minus one bit of color, but it offends! I’ve battled Photoshop for a while on this, but I just can’t seem to get exactly what I want out of it. So to make a perfect gradient, I decided to write some code. The requirements are simple: given a starting color and a set of deltas, output a perfect gradient.

Here are some quick examples:

1
gradient1
2
gradient2
3
gradient3
#000000
4, 1, 0.25
#eeeeff
-2.2, -1, -0.3
#ff0099
-1, 0, 1
 

If we zoom in on example #1, which starts with black (#000000) and has deltas of 4, 1, 0.25, we see the following:

zoomed gradient
 

The diagram shows the first ten rows of the gradient. The delta values are accumulated with each row, and only the whole part of the resulting color value is used (aka I take the floor of each color bit). So in this example, using the fractional delta of 0.25 results in exactly one additional blue bit every four rows. Ahhh, perfect!

The Code

No need to use some fancy new language, I wrote a simple PHP program to handle commandline input and output a perfect PNG gradient. The interesting part is the function that generates and saves the gradient:

function build_image($filename, $w, $h, $color, $delta) {
  $img = imagecreatetruecolor($w, $h);
 
  $c = imagecolorallocate($img, $color[0], $color[1], $color[2]);
  $d = $delta;
 
  for ($y = 0; $y < $h; $y++) {
    imagefilledrectangle($img, 0, $y, $w - 1, $y + 1, $c);
 
    $c = imagecolorallocate($img,
      clamp(floor($color[0] + $d[0])),
      clamp(floor($color[1] + $d[1])),
      clamp(floor($color[2] + $d[2]))
    );
 
    $d = array($d[0] + $delta[0], $d[1] + $delta[1], $d[2] + $delta[2]);
  }
 
  imagepng($img, $filename);
  imagedestroy($img);
}

The code is straight forward. First, create the image via imagecreatetruecolor(). Then, starting with the starting color, draw a one pixel tall rectangle for each row of the image. The next row’s color is computed in each iteration by adding the accumulated delta to the starting color. Finally, output the image as a PNG via imagepng() and free the memory. The complete php source can be downloaded here.

Button Time

Once we have our perfect gradient engine in place, it’s time to make some perfect buttons. To achieve the standard glass button look-and-feel, I typically fuse two gradients together: light on the top, dark on the bottom.

Here are the two halves of a pretty red button, along with their starting color and deltas:

TOP
BOTTOM
top
bottom
#ff8080
-3,-3,-3
#d23c3c
-3,-3,-3
 

And the two commandline invocations of gradient.php to create the gradients:

php gradient.php 100x16 ff8080 -3,-3,-3 top.png
php gradient.php 100x16 d23c3c -3,-3,-3 bottom.png

If I want my buttons to be sexy, rounded corners are a must. My favorite photoshop trick to create multiple rounded buttons is to use a rounded alpha-transparent button with each gradient as a clipping mask. Using a clipping mask is a simple way to guarantee button geometry remains fixed while colors are changed.

Here is the layers pane showing the two gradients fused together and used as a clipping mask for the rounded alpha-transparent button:

clip mask
 

The result is a horizontally stretchable gradient button, that doesn’t look half bad. See for yourself:

button
 

Custom UIButton

The final button asset can be used as desired, but here is a simple Objective-C example since I’ve been in iPhone world lately:

UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
[btn setFrame:CGRectMake(20, 20, 140, 32)];
[btn setBackgroundImage:[[UIImage imageNamed:@"btn-red.png"]
      stretchableImageWithLeftCapWidth:10.0
      topCapHeight:0.0] forState:UIControlStateNormal];
[btn setTitle:@"BUTTON" forState:UIControlStateNormal];
[btn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[btn.titleLabel setFont:[UIFont boldSystemFontOfSize:14]];

Create a new UIButton of type UIButtonTypeCustom and then set the button skin as the backgroundImage. The horizontal stretchability is due to the stretchableImageWithLeftCapWidth and topCapHeight.

Here is a screenshot from the iPhone simulator showing the button in action:

screenshot
 
Files
  • gradient.php – the perfect gradient engine
  • gradient-button.psd – the photoshop source for the red button image, including the rounded alpha-transparent button and fused red gradients
  • btn-red.png – the red button image

 6.3

Going from SVG data to a Degrafa Path couldn’t be easier: just copy & paste. You can watch this video tutorial or you can check out this demo.

But there is one trick for Inkscape: even though the coordinate origin on the Inkscape document is the normal cartesian origin in the bottom left and the y-axis points up, the SVG output always uses the upper left corner of the document as the origin and the y-axis points down (per the SVG Spec, § 7.3).

To demonstrate, I created a new document in Inkscape, set my dimensions to 500 x 500, and placed a simple path (which happens to be a square) in the upper left corner:

square

You can see by the rulers in Inkscape that the square’s origin is at (0,500).

If we save our square and examine the SVG output, we see:

<svg ...>
  <g ...>
    <path d="M 0,0 L 100,0 L 100,100 L 0,100 L 0,0 z" />
  </g>
</svg>

If we ignore everything in the file except the relevant path data, we can see the very first path command is M 0,0 which is path-speak for move to (0,0). This is exactly as expected from the SVG spec: upper left is the coordinate origin. The cartesian origin in Inkscape is bogus!

Next, we can just copy the path data from the SVG file and paste it into the data attribute of a Degrafa Path component.

<Degrafa:Path data="M 0,0 L 100,0 L 100,100 L 0,100 L 0,0 z">
    <Degrafa:fill>
        <Degrafa:SolidFill color="#EECCEE" />
    </Degrafa:fill>
    <Degrafa:stroke>
        <Degrafa:SolidStroke color="#FF00FF" weight="3" />
    </Degrafa:stroke>
</Degrafa:Path>

Give it a fill color and a stroke color, and we get a pretty purple square. Now I know my Degrafa Path component will have a square in the upper left, because I know my square was in the upper left in Inkscape. Nice and easy.

Files

 3.4

A while back I started digging into the WindowShade component in Flexlib. I really needed a set of cool collapsable buckets for a project at work, and WindowShade was perfect for the task. Alas, I couldn’t find too much info on styling a WindowShade other than Doug McCune’s awesome example of WindowShade and Degrafa. So, here is how I went about achieving the look and feel I needed with WindowShade.

Plain Vanilla

I started with an unstyled, super vanilla WindowShade wrapping a List. And of course, I get this super-vanilla output:

shade 1 (view source enabled)

The only styling magic was to add padding="0" to the WindowShade to get the child List component to suck up to the bottom of the WindowShade button.

My First Attempt

In the next pass, I ditched the lame WindowShade button, and went with Flexlib’s CanvasButton, which contains a simple Label plus a CheckBox skinned with a plus or minus graphic. The code:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
        xmlns:mx="http://www.adobe.com/2006/mxml"
        xmlns:flexlibContainer="flexlib.containers.*"
        xmlns:flexlibControl="flexlib.controls.*"
        viewSourceURL="srcview/index.html">
 
    <mx:Script>
    <![CDATA[
        [Bindable]
        private var goodies:Array = [
            { header:'Ice Cream', items:['Vanilla', 'Chocolate', 'Strawberry', 'Cookies & Cream'] },
            { header:'Candy', items:['Twix', 'Snickers', 'Fire Balls', 'Hot Tamales', 'Mike & Ikes', 'Pez'] },
            { header:'Cookies', items:['Chewy Chips Ahoy', 'Mint Milano', 'Oreo', 'Nutter Butter', 'Fig Newtons'] }];
    ]]>
    </mx:Script>
 
    <mx:Style source="style.css" />
 
    <mx:VBox width="140" styleName="container">
        <mx:Repeater id="r" dataProvider="{goodies}">
            <flexlibContainer:WindowShade width="100%" styleName="shade"
                    data="{r.currentItem.header}"
                    opened="{r.currentIndex == 0}">
                <flexlibContainer:headerRenderer>
                    <mx:Component>
                        <flexlibControl:CanvasButton width="100%" height="30" styleName="shadeBtn">
                            <mx:Script>
                            <![CDATA[
                                import flexlib.containers.WindowShade;
                            ]]>
                            </mx:Script>
 
                            <mx:Label id="header" top="3" left="4" text="{WindowShade(parent).data}" styleName="shadeHead"/>
                            <mx:CheckBox id="chk" top="9" right="6" selected="{WindowShade(parent).opened}" styleName="shadeChk"/>
                        </flexlibControl:CanvasButton>
                    </mx:Component>
                </flexlibContainer:headerRenderer>
 
                <mx:List width="100%" dataProvider="{r.currentItem.items}" rowCount="{r.currentItem.items.length}" styleName="shadeList"/>
            </flexlibContainer:WindowShade>
        </mx:Repeater>
    </mx:VBox>
</mx:Application>

After throwing in some colors from a sweet Kuler theme and embedding Helvetica, we get this:

shade 2 (view source enabled)

At this point, I was really happy with look and feel, but there we still a few minor issues with the CanvasButton header that needed to be fixed before declaring victory.

Fixups

First, I needed the rollover event to flow down to the checkbox, so it would correctly show the overSkin on mouse over. Second, I wanted a color change on the Label on rollover to provide better visual feedback to the user. And lastly, I wanted the entire CanvasButton header to be clickable, not just the label text or the checkbox graphic.

Focusing just on the modified CanvasButton code, used in the headerRendered:

<flexlibControl:CanvasButton width="100%" height="30" styleName="shadeBtn"
        rollOver="header.setStyle('color', 0xffffff); chk.dispatchEvent(event);"
        rollOut="header.setStyle('color', 0xcccccc); chk.dispatchEvent(event);">
    <mx:Script>
    <![CDATA[
        import flexlib.containers.WindowShade;
    ]]>
    </mx:Script>
 
    <mx:Label id="header" top="3" left="4" text="{WindowShade(parent).data}" styleName="shadeHead"/>
    <mx:CheckBox id="chk" top="9" right="6" selected="{WindowShade(parent).opened}" styleName="shadeChk"/>
    <mx:Canvas width="100%" height="100%" backgroundColor="#000000" backgroundAlpha="0" />
</flexlibControl:CanvasButton>

The final result, a nice styled WindowShade:

shade 3 (view source enabled)

I used the parent CanvasButton’s rollover event to set the child Label color and forward the event to the child CheckBox. To make the entire button clickable, I used one of my favorite Flex UI hacks: I added a space-filling transparent Canvas.

Comparison Shopping

And finally, a side-by-side comparison of all three WindowShade skins:

Flash is required. Get it here!

Update: See my Drawer Component in Flex 4 post for a custom collapsible drawer component written from scratch in Flex 4.


 2.8

Flex is awesome. In many ways, it’s the right tool for the job of bringing beautiful design to the web. I use flex every day at work, and also at home on my own fun projects. Today’s challenge is to take a very simple blog design and re-implement it in flex.

In The Red Corner

I’ll start with my simple two-column blog design that I like to call Circles of Doom. The original design was done in Inkscape, and assembled for the web using Blueprint CSS. You can read all the gory details of the design and assembly in a series of earlier posts: part 1, part 2, part 3, part 4.

Skipping right to the end result, you can view the final results here:

 

In The Blue Corner

Flex provides a lot of design leverage with its support for fills & strokes, gradients, rounded corners, and filters like drop shadow and glow. The original html design required the use of images to handle these features, but Flex’s CSS is powerful enough to handle everything with the exception of the blood red background circles.

The design architecture can be thought of as a simple three layer structure show here:

flex layers diagram

The bottom layer has the blood red background circle image. It is absolutely positioned vertically (y="-65") and horizontally centered (x="{(this.width - 950)/2}"). Like this:

<mx:Image source="@Embed(source='assets/circ.png')"
        x="{(this.width - 950)/2}" y="-65" />

The middle layer has the main box with rounded corners and a black glow. Like this:

<mx:VBox width="870" x="{(this.width - 870)/2}" y="130" styleName="body">
    <mx:filters>
        <mx:GlowFilter blurX="22" blurY="22" color="#111111" alpha="0.6" />
    </mx:filters>
</mx:VBox>

And the Flex CSS:

VBox.body {
	horizontalAlign: center;
	backgroundColor: #ffffff;
	borderStyle: solid;
	borderThickness: 10;
	borderColor: #886655;
	cornerRadius: 28;
	verticalGap: 10;
	paddingTop: 20; paddingBottom: 4;
}

And the top layer has the main content, sidebar & sidebar content, and footer. Like this:

<mx:Canvas width="790">
    <mx:Text text="main" width="590" styleName="contentTxt" />
 
    <mx:VBox width="190" x="600" styleName="sidebar">
        <mx:Text text="sidebar" width="100%" styleName="sidebarTxt" />
    </mx:VBox>
</mx:Canvas>
 
<mx:Text textg="footer" styleName="footerTxt" />

And the associated Flex CSS:

Text.contentTxt {
	fontFamily: Arial;
	fontSize: 12;
	fontWeight: normal;
	color: #000000;
}
 
VBox.sidebar {
	backgroundColor: #aa1100;
	borderStyle: solid;
	borderThickness: 2;
	borderColor: #ff2200;
	cornerRadius: 12;
	paddingLeft: 10; paddingRight: 10;
	paddingTop: 10; paddingBottom: 10;
}
 
Text.sidebarTxt {
	fontFamily: Arial;
	fontSize: 12;
	fontWeight: normal;
	color: #ffffff;
}
 
Text.footerTxt {
	fontFamily: Arial;
	fontSize: 10;
	fontWeight: normal;
	color: #886655;
}
The Result

Put it all together with some dummy Lorem ipsum text and you get a decent looking Flex blog design (just right-click, and select “view source” to see the code). It compares favorably to the original html design. The only obvious difference is the browser font rendering versus Flex’s font rendering.

The Files

© 2010 saturnboy.com