Saturnboy
 3.4

Styling Flexlib’s WindowShade

, , ,

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.


Comments

sandeep

3.26.2009

1

Hi,

Happened to do the same thing what you and faced the same problem and the only difference is that i couldn’t resolve the issue you faced. I am not able to roll over or roll out a windowshade when clicked on Windowshade apart from the label. I have included a Label with in the Windowshade but it has made windowshade rolldown functionality to fail. Can you please look at the code and let me know where things have failed, I have tried all the possible ways but failed.

Please find my code below…

and my actionscript methods…

public static function onBackDown(event:Event):void {
ModelLocator.getInstance().dispatchEvent(new Event(“LabelClicked”));
}

public static function onBackClick(event:Event):void {
event.stopPropagation();
}

Would appreciate if you could suggest a solution…

Thanks

3.27.2009

2

As I mentioned above, I’m using a CanvasButton in the headerRenderer of the WindowShade. The CanvasButton hold three components: a Label, a CheckBox, and a basic Canvas. The key to making the entire CanvasButton clickable is the extra Canvas, which is space-filling and transparent:

<mx:Canvas width="100%" height="100%"
    backgroundColor="#000000" backgroundAlpha="0" />

Joel

2.22.2010

3

Excellent guide. Helped a ton. Thanks!

Umesh

5.19.2010

4

Hi,
Thanks for a very good example. I wanted to know how can I have a different header colors applied. I want the header to have a one color when window shade is open and another color when it is closed.

Any help will be much appreciated. Using the most recent Flex 4 version.

5.19.2010

5

@Umesh: If you want to change the style at runtime, the easiest thing to do is to use getStyle() and setStyle().

So, if I wanted to switch styles on the header on open & close, I just listen for the correct events and use setStyle() to make the switch.

shade.addEventListener(WindowShadeEvent.OPEN_BEGIN,
    function(e:Event):void {
        shade.setStyle('headerStyleName', 'headOpen');
    });
shade.addEventListener(WindowShadeEvent.CLOSE_END,
    function(e:Event):void {
        shade.setStyle('headerStyleName', 'headClose');
    });

And then define two CSS styles for headOpen and headClose with different background colors.

Good luck.


Leave a Comment
(required)
(required)
© 2010 saturnboy.com