Creating a custom MX Accordion header skin in Flex 4

The following example shows how you can style the MX Accordion header (with default Spark skin) in Flex 4 by creating a new skin based on the default Spark skin and modifying the various skin parts.

The following example(s) require Flash Player 10 and the Adobe Flex 4 SDK. To download the Adobe Flash Builder 4 trial, see www.adobe.com/products/flex/. To download the latest nightly build of the Flex 4 SDK, see opensource.adobe.com/wiki/display/flexsdk/Download+Flex+4.

For more information on getting started with Flex 4 and Flash Builder 4, see the official Adobe Flex Team blog.

<?xml version="1.0" encoding="utf-8"?>
<!-- http://blog.flexexamples.com/2009/06/21/creating-a-custom-halo-accordion-header-skin-in-flex-4/ -->
<s:Application name="Accordion_SparkSkin_headerStyleName_skin_test"
        xmlns:fx="http://ns.adobe.com/mxml/2009"
        xmlns:mx="library://ns.adobe.com/flex/mx"
        xmlns:s="library://ns.adobe.com/flex/spark">
 
    <fx:Style>
        .customAccordionHeadStyles {
            skin: ClassReference("skins.CustomAccordionHeaderSkin");
        }
    </fx:Style>
 
    <mx:Accordion id="accordion"
            headerStyleName="customAccordionHeadStyles"
            left="20" right="20" top="20" bottom="20">
        <mx:VBox label="Red" width="100%" height="100%">
            <mx:Text text="Panel 1" />
        </mx:VBox>
        <mx:VBox label="Orange" width="100%" height="100%">
            <mx:Text text="Panel 2" />
        </mx:VBox>
        <mx:VBox label="Yellow" width="100%" height="100%">
            <mx:Text text="Panel 3" />
        </mx:VBox>
        <mx:VBox label="Green" width="100%" height="100%">
            <mx:Text text="Panel 4" />
        </mx:VBox>
        <mx:VBox label="Blue" width="100%" height="100%">
            <mx:Text text="Panel 5" />
        </mx:VBox>
    </mx:Accordion>
 
</s:Application>

[HaloSparkSkins]

And the custom Accordion header skin, skins/CustomAccordionHeaderSkin.mxml, is as follows:

<?xml version="1.0" encoding="utf-8"?>
<!-- http://blog.flexexamples.com/2009/06/21/creating-a-custom-halo-accordion-header-skin-in-flex-4/ -->
<s:SparkSkin name="CustomAccordionHeaderSkin"
        xmlns:fx="http://ns.adobe.com/mxml/2009"
        xmlns:s="library://ns.adobe.com/flex/spark" 
        minWidth="21" minHeight="21"
        alpha.disabled="0.5">
    <!-- states -->
    <s:states>
        <s:State name="up" />
        <s:State name="over" />
        <s:State name="down" />
        <s:State name="disabled" />
        <s:State name="selectedUp" />
        <s:State name="selectedOver" />
        <s:State name="selectedDown" />
        <s:State name="selectedDisabled" />
    </s:states>
 
    <fx:Script>
        <![CDATA[
            override protected function initializationComplete():void {
                useChromeColor = true;
                super.initializationComplete();
            }
        ]]>
    </fx:Script>
 
    <!-- layer 3: fill -->
    <s:Rect left="1" right="1" top="1" bottom="1">
        <s:fill>
            <s:SolidColor color="white"
                          color.up="red"
                          color.over="haloOrange"
                          color.down="yellow"
                          color.selectedUp="haloGreen"
                          color.selectedOver="haloBlue"
                          color.selectedDown="purple" />
        </s:fill>
    </s:Rect>
 
    <!-- layer 4: fill lowlight -->
    <s:Rect left="1" right="1" top="1" bottom="1">
        <s:fill>
            <s:LinearGradient rotation="270">
                <s:GradientEntry color="0x000000" ratio="0.0" alpha="0.0627" />
                <s:GradientEntry color="0x000000" ratio="0.48" alpha="0.0099" />
                <s:GradientEntry color="0x000000" ratio="0.48001" alpha="0" />
            </s:LinearGradient>
        </s:fill>
    </s:Rect>
 
    <!-- layer 5: fill highlight -->
    <s:Rect left="1" right="1" top="1" bottom="1">
        <s:fill>
            <s:LinearGradient rotation="90">
                <s:GradientEntry color="0xFFFFFF"
                                 ratio="0.0"
                                 alpha="0.33" 
                                 alpha.over="0.22" 
                                 alpha.down="0.12"/>
                <s:GradientEntry color="0xFFFFFF"
                                 ratio="0.48"
                                 alpha="0.33"
                                 alpha.over="0.22"
                                 alpha.down="0.12" />
                <s:GradientEntry color="0xFFFFFF"
                                 ratio="0.48001"
                                 alpha="0" />
            </s:LinearGradient>
        </s:fill>
    </s:Rect>
 
    <!-- layer 6: highlight stroke (all states except down) -->
    <s:Rect left="1" right="1" top="1" bottom="1" excludeFrom="down">
        <s:stroke>
            <s:LinearGradientStroke rotation="90">
                <s:GradientEntry color="0xFFFFFF" alpha.over="0.22" />
                <s:GradientEntry color="0xD8D8D8" alpha.over="0.22" />
            </s:LinearGradientStroke>
        </s:stroke>
    </s:Rect>
 
    <!-- layer 6: highlight stroke (down state only) -->
    <s:Rect left="1" top="1" bottom="1" width="1" includeIn="down">
        <s:fill>
            <s:SolidColor color="0x000000" alpha="0.07" />
        </s:fill>
    </s:Rect>
    <s:Rect right="1" top="1" bottom="1" width="1" includeIn="down">
        <s:fill>
            <s:SolidColor color="0x000000" alpha="0.07" />
        </s:fill>
    </s:Rect>
    <s:Rect left="1" top="1" right="1" height="1" includeIn="down">
        <s:fill>
            <s:SolidColor color="0x000000" alpha="0.25" />
        </s:fill>
    </s:Rect>
    <s:Rect left="1" top="2" right="1" height="1" includeIn="down">
        <s:fill>
            <s:SolidColor color="0x000000" alpha="0.09" />
        </s:fill>
    </s:Rect>
 
    <!-- layer 2: border -->
    <s:Rect left="0" right="0" top="0" bottom="0"
            width="69" height="20">
        <s:stroke>
            <s:SolidColorStroke color="0x696969" 
                                alpha="1" 
                                alpha.over="1" 
                                alpha.down="1" />
        </s:stroke>
    </s:Rect>
 
</s:SparkSkin>

This entry is based on a beta version of the Flex 4 SDK and therefore is very likely to change as development of the Flex SDK continues. The API can (and will) change causing examples to possibly not compile in newer versions of the Flex 4 SDK.

14 thoughts on “Creating a custom MX Accordion header skin in Flex 4

  1. If there’s any other unfortunates like me browsing this page trying to get the Accordion skin to work well with the flex4, here comes a solution to set also a customized label skin:

    First of all, set a creationComplete handler, in the skin class definition:
    creationComplete=”onCreationComplete(event)”

    After that, just add this script tag, with some magic code to get a reference of the original mx component:

    After that you can access the properties of your original mx component like this:

    This solution is just a complement to the article above, and is not a beautiful one. Hope that in the future someone come with a better and easier solution for this issue.

  2. If there’s any other unfortunates like me browsing this page trying to get the Accordion skin to work well with the flex4, here comes a solution to set also a customized label skin:

    First of all, set a creationComplete handler, in the skin class definition:
    creationComplete=”onCreationComplete(event)”

    After that, just add this script tag, with some magic code to get a reference of the original mx component:

    After that you can access the properties of your original mx component like this:

    This solution is just a complement to the article above, and is not a beautiful one. Hope that in the future someone come with a better and easier solution for this issue.

  3. Shit, I can’t past the flex code here… the system keeps stripping my code….

    This, should be placed inside a fx:Script tag….

    import mx.events.FlexEvent;
     
    [Bindable]
    public var __parent:*;
     
    protected function onCreationComplete(event:FlexEvent):void{
    	//Get a reference to the "hostComponent", needed to be used like this 
    	//because I couldn't make the metadata hostComponent work for the mx:VBox component
    	__parent = this["parent"];
    	//Hide the original label of flex component
    	__parent.getChildAt(0).visible = false;
    }

    and after that you can use the __parent variable to access the information of the original mx component, just like the hostComponent should work…
    In my example I set the first child to false, to hide the original label of mx component… then you should specify another label element and you can retrieve the string value like this:
    text=”{__parent.label}”

  4. If you want to make your header a flat gradient, and not use the highlights, my assumption would be that you could simple comment out the other fill layers and just use layer 3 (changing the gradient fill colors accordinly).

    But when I do this, I get a strange shift in color where the colors look much darker than the values I’m putting in. This is probably my ignorance of the skinning framework (maybe the baseLayer attribute is somehow modifying the colors I enter).

    Any thoughts on trying to do a flat gradient for the header.

    As always, thanks for this immensely helpful site.

    Daniel McQ

  5. …and as usual the answer is pretty obvious on second glance: commenting out the

    useBaseColor = true;

    line allows level3 to show unmodified colors.

    DMcQ

  6. i have a question…

    i want to switch between 2 or more stlyes , can i use a function to change directly the css file??

    thanks.

    1. @AlCapone,

      Sure, I’d just create an ActionScript function which sets the headerStyleName style to whatever whichever custom style you want. Basically make 2-3+ custom selectors and specify the custom Accordion header skin you want to use:

      .customAccordionHeadStyles1 {
          skin: ClassReference("skins.CustomAccordionHeaderSkin1");
      }
      .customAccordionHeadStyles2 {
          skin: ClassReference("skins.CustomAccordionHeaderSkin2");
      }
      .customAccordionHeadStyles3 {
          skin: ClassReference("skins.CustomAccordionHeaderSkin3");
      }

      And then create some ActionScript functions to set the headerStyleName to whichever CSS selector you want:

      private function useSkin1():void {
          accordion.setStyle("headerStyleName", "customAccordionHeadStyles1");
      }
      private function useSkin2():void {
          accordion.setStyle("headerStyleName", "customAccordionHeadStyles2");
      }
      private function useSkin3():void {
          accordion.setStyle("headerStyleName", "customAccordionHeadStyles3");
      }

      You could probably clean up that code significantly, but it may help get you started.

      Peter

  7. Could you please direct on how we change the accordian header text color in Flex4 skinng. I tried to add
    this label component and it doesn’t seem to be working.Thanks in advance.

    1. @Priya,

      Not sure what you’re trying to do with skinning, but can’t you just set the headerStyleName style on the Accordion and set the color style there?

      <?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">
       
          <fx:Style>
              @namespace s "library://ns.adobe.com/flex/spark";
              @namespace mx "library://ns.adobe.com/flex/mx";
       
              .headerStyles {
                  chromeColor: black;
                  color: white;
              }
          </fx:Style>
       
          <mx:Accordion id="acc1"
                  headerStyleName="headerStyles"
                  width="300" height="200"
                  horizontalCenter="0" verticalCenter="0">
              <s:NavigatorContent id="navCon1" label="One" />
              <s:NavigatorContent id="navCon2" label="Two" />
              <s:NavigatorContent id="navCon3" label="Three" />
          </mx:Accordion>
       
      </s:Application>

      Peter

  8. Hi peter,

    can we maintain the text color for all states of Accordion Header?

    currently i set the
    .headerStyle{
    color : ’0xFFFFFF’;
    text-roll-over-color : ’0xFFFFFF’;
    text-selected-color: ’0xFFFFFF’;
    }

    Bur on down or over state text color is black.

    Thanks

Comments are closed.