Home > Panel > Creating Collapsible Panel in Flex 4

Creating Collapsible Panel in Flex 4

September 8th, 2009 Leave a comment Go to comments

It is quite common in Flex applications (and other RIAs) to divide screen content into two parts: the navigation/configuration panel on the left and the actual content on the right.
The examples of such apps are FlexStore sample and famous Style Explorer.

I followed this pattern in many projects and several times we come to the point that navigation/configuration panel requires too much space and that there should be a possibility to minimize it. Probably designers of Style Explorer has a similar idea since their navigation control can be minimized. Unfortunately they haven’t created reusable component to do this.

Some time ago I have created the collapsible panel in Flex 3. The idea of this component was to minimize panel by hiding panel content and rotating the header by 90 degree. So that, minimized panel was visible as vertical bar with the title. It was the nightmare to use rotation in Flex 3 since Flex 3 layouts doesn’t care about rotation. Placing component in the right place requires many tricks and extensive usage of trigonometric functions…

When I read that Gumbo (now Flex 4) layouts supports rotation I decided to test it by reimplementing my collapsible panel. Flex 4 definitely passed the test. Spark component architecture is really cool and it is much easier to create reusable/extendible components in Flex 4 than it was before. You can see the result of my work below.

This example is created using 4.0.0.8847, it will not work with SDK shipped with beta 1.
View source is enabled, you can download zipped sources from here.

Following Spark components architecture I have extended Panel class and created new MXML skin.

Component class

Below you can find the list of steps taken to create CollapsiblePanel main component class. At first sight this list may look long and complicated but after understanding Spark architecture it is really simple.

  • Adding “collapsed” skin state
    [SkinState("collapsed")]
    public class CollapsiblePanel extends Panel
    {
    
  • Adding new collapsed field indicating if panel is collapsed (invalidating skin state in setter)
    public function get collapsed():Boolean
    {
    	return _collapsed;
    }
    public function set collapsed(value:Boolean):void
    {
    	_collapsed = value;
    	invalidateSkinState();
    }
    protected var _collapsed:Boolean;
    
  • Overriding getCurrentSkinState() function to support “collapsed” skin state
    override protected function getCurrentSkinState():String
    {
    	return collapsed ? "collapsed" : super.getCurrentSkinState();
    }
    
  • Adding collapseButton optional skin part
    [SkinPart(required="false")]
    public var collapseButton:Button;
    
  • Implementing handler to toggle collapsed property on collapseButton click
    protected function collapseButtonClickHandler(event:MouseEvent):void
    {
    	collapsed = !collapsed;
    }
    
  • Overriding partAdded()/partRemoved() functions to add collapseButton event handler
    override protected function partAdded(partName:String, instance:Object) : void
    {
    	super.partAdded(partName, instance);
    	
    	if (instance == collapseButton)
    	{
    		Button(instance).addEventListener(MouseEvent.CLICK, collapseButtonClickHandler);
    	}
    }
    override protected function partRemoved(partName:String, instance:Object) : void
    {
    	if (instance == collapseButton)
    	{
    		Button(instance).removeEventListener(MouseEvent.CLICK, collapseButtonClickHandler);
    	}
    	super.partRemoved(partName, instance);
    }
    

MXML Skin

The CollapsiblePanelSkin.mxml skin is a copy of default Spark Panel skin with a number of modification. I used enhanced styles syntax to modify skin in “collapsed” state.

  • Adding “collapsed” state
    <s:states>
        <s:State name="normal" />
        <s:State name="collapsed" />
        <s:State name="disabled" />
    </s:states>
    
  • Grouping all title bar layers inside one Group tag
    <s:Group id="titleBarGroup" left="0" top="0" right="0" bottom="0" 
         maxHeight="32" rotation.collapsed="90">
    
  • Adding collapse button
    <s:Button id="collapseButton" width="16" height="16" top="7" right="7"
        label="-" label.collapsed="+" toolTip="Collapse" toolTip.collapsed="Open" />
    
  • Excluding contentGroup from collapsed state
    <s:Group id="contentGroup" left="1" right="1" top="32" bottom="1" minWidth="0" minHeight="0" 
         visible.collapsed="false" excludeFrom="collapsed">
    </s:Group>
    
  • Adding transitions
    <s:transitions>
        <s:Transition fromState="normal" toState="collapsed">
            <s:Sequence>
                <s:Fade target="{contentGroup}" duration="250" />
                <s:Parallel targets="{[titleBarGroup, this]}" >
                    <s:Rotate target="{titleBarGroup}" duration="250" />
                    <s:Resize target="{this}" duration="250" easer="{collapseEaser}" />
                </s:Parallel>
            </s:Sequence>
        </s:Transition>
        <s:Transition fromState="collapsed" toState="normal">
            <s:Sequence>
                <s:Parallel targets="{[titleBarGroup, this]}" >
                    <s:Rotate target="{titleBarGroup}" duration="250" />
                    <s:Resize target="{this}" duration="250" easer="{uncollapseEaser}" />
                </s:Parallel>
                <s:Fade target="{contentGroup}" duration="250" />
            </s:Sequence>
        </s:Transition>
    </s:transitions>
    

Summarizing, creating CollapsiblePanel in Flex 4 was much easier than in Flex 3 and the resulting component is of much higher quality. Although understanding Spark components architecture and MXML 2009 may require some time it is definitely worth doing!

Categories: Panel Tags: , , ,
  1. RDB
    September 15th, 2009 at 14:09 | #1

    Great, thank you.

  2. Dileep
    September 22nd, 2009 at 15:07 | #2

    Hi,
    Thanks for great work…but source code is not available ..can u post it again????????
    Regards
    Dileep

  3. Iwo Banas
    September 23rd, 2009 at 00:40 | #3

    Hi,
    I have corrected paths to the sources. You can download it from here. Unfortunately html source view generated by FB4 is incomplete but zipped sources are OK.
    Iwo

  4. vtrinity
    October 1st, 2009 at 22:56 | #4

    Thanks for posting these examples !

  5. Karthik
    October 14th, 2009 at 13:42 | #5

    Hi,
    Thanks for sharing collapsible panel. im trying to get a Collapsible Panel in flex 3. can you provide some direction to achieve the same.

    thanks

  6. Thomas
    October 15th, 2009 at 11:46 | #6

    Hi,
    nice component. But it doesn’t really work when the panel has an explicit width. It get’s minimized but the border, shadow and background keep their width. I tried to put two of this panels inside a DividedBox. Everything works fine until you resize the box (or give the panel an explicit width). Perhaps you can fix this?

  7. Iwo Banas
    October 15th, 2009 at 13:27 | #7

    Hi Thomas,
    This is rather the demo of Flex 4 potential than the complete component so some other features may not work as well. To fix your problem you can set explicit and percent width to NaN when panel is being collapsed and restore them to previous values when it is un-collapsed. You can do that by adding two “backup variables” and modifying collapsed setter:

    public function set collapsed(value:Boolean):void
    {
        if (value)
        {
            uncollapsedExplicitWidth = explicitWidth;
            uncollapsedPercentWidth = percentWidth;
            explicitWidth = NaN;
            percentWidth = NaN;
        }
        else
        {
            explicitWidth = uncollapsedExplicitWidth;
            percentWidth = uncollapsedPercentWidth;
        }
        _collapsed = value;
        invalidateSkinState();
    }
    protected var _collapsed:Boolean;
    protected var uncollapsedPercentWidth:Number = NaN;
    protected var uncollapsedExplicitWidth:Number = NaN;
    

    If you would like to polish this component I can add it to the reusable-fx google project so that you can share your changes. Give me a note if you are interested.

  8. Thomas
    October 15th, 2009 at 13:49 | #8

    Hi,

    thank’s for your code – I have thought of something in the same way. I’m just playing around with Flex 4 stateful skins and am evaluating to use this kind of panel for the application I am going to build. If I do further modification I’ll give you a note :-)

  9. Iwo Banas
    October 15th, 2009 at 14:06 | #9

    Hi Karthik,

    As you can read above creating collapsible panel in Flex 3 is much harder than in Flex 4 because Flex 3 layouts doesn’t care about rotation. Here are some key concepts regarding my implementation (I can’t share the code since it is copyrighted to my ex-employer):

    - CollapsiblePanel extends Canvas and contains standard Panel.

    - Panel is placed/rotated inside Canvas using absolute layout (some calculations are necessary to determine correct x/y/width/height during animation.

    - addChild, addChildAt etc. functions are overridden to pass child to inner Panel.

    - Animation is done using AnimateProperty Prallel and Sequence.

    Also remember to use embedded font (other ways all texts disappear after rotation).
    All in all, the resulting components code looks quite dirty and is in no way as reusable/extendible as Flex 4 code.

    Good luck creating your component! And don’t forget to show us the result of your work :-)

  10. Karthik
    October 19th, 2009 at 13:25 | #10

    @Iwo Banas
    Thanks for the direction. Will work on it and sure will post the code.
    think the embedded font will do the trick. i got stuck , when the title text disappeared.

    -Karthik

  11. lynxoid
    April 27th, 2010 at 20:21 | #11

    nice work. now i have to play around w/ skinning in Flex4

  12. Nikos
    June 23rd, 2010 at 14:21 | #12

    Awesome, I take it works fine with the released version?

  13. July 18th, 2010 at 18:20 | #13

    Hello,
    I applied your component successfully. However in my project, there are other states for the Application resize: one is “expanded” and one is “closed”. Only in state “expanded” we will touch the CollapsiblePanel (collapsed/normal states).

    In the skin parts, the contentGroup, titleBarGroup and the collapsible button are still remain unchanged when resize.

    Have we got any solution for this?

    Thanks.

  14. Cubba
    July 28th, 2010 at 11:05 | #14

    thanks a lot!! i needed similar component for my job

  15. Anonymous
    August 9th, 2010 at 18:45 | #15

    Hi,

    Is there a way to make this component generalizable to work with any theme? I realize the button in the panel would need to be designed and skinned, but is there a way to get the panel’s skin to just “inherit” the colors/fonts/etc of the Panel objects as skinned by the current theme?

    I tried removing sections where you explicitly defined colors and fontsizes, as well as a few other things, but instead of inheriting the Panel skin in use, I just got a plain looking Collapsible Panel.

    Any thoughts?

  16. Michal
    September 13th, 2010 at 17:06 | #16

    Thank you for this example!

    Could I have a question? I would like to know if is possible to use this scenario also for maximizing the panel. I tried to add another state “maximized” and set all neccessary things. But I have problem with setting the percent width and height to the skin class. The percent settings doesn’t apply on the panel component. For maximizing I need to use 100% width and height. Is possible to do that in skin class?

    Thank You!

  17. November 24th, 2010 at 18:47 | #17

    Wow! Thanks for the great post!!!

  18. Shan
    February 3rd, 2011 at 06:22 | #18

    Thank you! I found this very useful, but I can’t get it to work in Google Chrome from the source code. However, the example on this page works fine. Anyone else having an issue in Chrome?

  19. jonnie
    March 12th, 2011 at 00:06 | #19

    hi.
    i’ve trying to use your component but i’m getting the following error:
    css type selectors are not suported in components

    for what i understand of flex, it’s not implementing the css.
    can you give some ideas on how to solve this?

  20. Ravi
    April 5th, 2011 at 11:05 | #20

    Hi,

    I have tried your collapsible panel very nice.
    But I got the problem when I want to change the direction of collapse panel. Could you please help me with this.

  21. Ravi
    April 5th, 2011 at 11:07 | #21

    I wanted to collapse panel in opposite direction than the default direction.

  22. Ashish
    April 18th, 2011 at 11:15 | #22

    Dear friend,
    Nice component. Thanks a lot. But could you please tell me how can we use this to build a CollapsiblePanel where header remains same, only the contents part height changes to zero on collapse and retain on open.

    Thanks for your reply

  23. Bruno
    May 6th, 2011 at 05:51 | #23

    The collapse function isn’t working even using last update (Thomas question)
    Is there any updates?

  24. Ken
    May 27th, 2011 at 23:21 | #24

    Great work !

    But it seems that the collapse button cannot have a label…

    “label=”-” label.collapsed=”+” ” doesn’t work…

  25. Marcua Baffa
    May 30th, 2011 at 13:38 | #25

    Hi,

    I Have a Flex 4.0 project using your collapsible panel. Now I have Flex 4.5. I tried to import the same project and there was an error of property missing in the collapsible panel.
    Are you aware of that ???
    Could you update your code to fix this problem.

    Thanks in aadvance

  26. Sam
    June 20th, 2011 at 05:30 | #26

    Hi,

    May i know how do i change the titlebar color on collapsed?

    Because when it is not in collapsed state, i setting my titlebar to be white? I want it to however change to another color in collapsed state.

    How can i achieve that?

    Thanks!

  27. Sam
    June 20th, 2011 at 06:56 | #27

    @Sam

    I have managed to solve it already. Thanks.

  28. June 30th, 2011 at 21:33 | #28

    @Marcua Baffa
    You could also update the code your self in the spirit of open source and post the fix here.

    Ries

  29. Kinjal
    July 30th, 2012 at 18:54 | #29

    can anyone please guide me how i can implement this in flex 4.5.1 ? i m getting error in flex 4.5.1 with this code….Please help me….

  30. Kinjal
    July 30th, 2012 at 18:56 | #30

    I m getting this error :
    The required skin state ‘disabledWithControlBar’ is missing.
    -The required skin state ‘normalWithControlBar’ is missing.
    -The required skin state ‘disabledWithControlBar’ is missing.

  31. Iwo Banas
    July 30th, 2012 at 19:47 | #31

    You need to add this two additional states to the skin. <s:State name="normalWithControlBar" stateGroups="withControls"/> <s:State name="disabledWithControlBar" stateGroups="withControls"/>

    Have a look at original 4.5.1 PanelSkin, you may want to include controlBarGroup in you skin as well.

  32. Priya
    August 28th, 2012 at 09:14 | #32

    I cannot solve the error for Simple text in Collapsible Panel Skin. If I change it to text input, I had to remove line break and vertical Align parameters. After I removed it also, I got the error
    “The required skin state ‘disabledWithControlBar’ is missing.
    -The required skin state ‘normalWithControlBar’ is missing.
    -The required skin state ‘disabledWithControlBar’ is missing”

    So I tried your above solution. And now I am getting

    The skin part type ‘spark.components:TextInput’ must be assignable to ‘spark.core:IDisplayText’. CollapsiblePanelSkin.mxml

    Could you please help me?

  33. Ragu
    August 2nd, 2013 at 18:07 | #33

    use RichText instead of SimpleText in panel skin. Add those two states which solves missing error.

  1. December 5th, 2009 at 22:02 | #1
  2. March 28th, 2010 at 19:42 | #2
  3. September 18th, 2012 at 16:35 | #3