0
votes

I coded a section component (border + title) that auto-fit the content (children) size.

Here is the component code:

<?xml version="1.0" encoding="utf-8"?>
<s:SkinnableContainer 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:Declarations>
        <!-- Placer ici les éléments non visuels (services et objets de valeur, par exemple). -->
    </fx:Declarations>

    <fx:Script>
        <![CDATA[
            [Bindable]
            public var title:String;
        ]]>
    </fx:Script>

</s:SkinnableContainer>

Here is the skin:

<?xml version="1.0" encoding="utf-8"?>

<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:fb="http://ns.adobe.com/flashbuilder/2009" alpha.disabled="0.5"
    creationComplete="fitContent(event)">

    <fx:Metadata>
    <![CDATA[ 
        /** 
         * @copy spark.skins.spark.ApplicationSkin#hostComponent
         */
        [HostComponent("component.GlassSectionComponent")]
    ]]>
    </fx:Metadata> 

    <fx:Script>
        <![CDATA[
            import mx.core.UIComponent;
            import mx.events.FlexEvent;

            override protected function initializationComplete():void{
                super.initializationComplete();
                this.contentGroup.addEventListener(Event.ADDED,fitContent,false);
            }

            private function fitContent(event:Event):void{
                this.minHeight = this.contentGroup.contentHeight + this.contentHeight - this.contentGroup.height;
                this.minWidth = this.contentGroup.contentWidth + this.contentWidth - this.contentGroup.width;
                this.invalidateSize();
                this.invalidateDisplayList();
            }
        ]]>
    </fx:Script>

    <s:states>
        <s:State name="normal" />
        <s:State name="disabled" />
    </s:states>

    <!-- border --> 
    <s:Path id="border" left="3" right="3" top="5" bottom="5"
            data="M 5 0
            L {this.titleDisplay.left-7} 0
            M {this.titleDisplay.left+this.titleDisplay.width} 0
            L {this.width-5} 0
            C {this.width} 0 {this.width} 0 {this.width} 5
            L {this.width} {this.height-5}
            C {this.width} {this.height} {this.width} {this.height} {this.width-5} {this.height}
            L 5 {this.height}
            C 0 {this.height} 0 {this.height} 0 {this.height-5}
            L 0 5
            C 0 0 0 0 5 0
            ">
        <s:filters>
            <s:GlowFilter alpha="0.5" blurX="10" blurY="10" color="0xffffff"
                          quality="5" strength="6"/>
        </s:filters>
        <s:stroke>     
            <s:SolidColorStroke id="borderStroke" weight="1" color="#ffffff" alpha="0.5"/>
        </s:stroke>
    </s:Path>


    <s:Label id="titleDisplay" maxDisplayedLines="1"
             left="{this.width*0.08}" top="0" bottom="0" minHeight="30"
             verticalAlign="top" textAlign="left" fontWeight="bold"
             text="{hostComponent.title}">
        <s:filters>
            <s:GlowFilter alpha="0.5" blurX="10" blurY="10" color="0xffffff"
                          quality="5" strength="6"/>
        </s:filters>
    </s:Label>

    <!--
        Note: setting the minimum size to 0 here so that changes to the host component's
        size will not be thwarted by this skin part's minimum size.   This is a compromise,
        more about it here: http://bugs.adobe.com/jira/browse/SDK-21143
    -->
    <!--- @copy spark.components.SkinnableContainer#contentGroup -->
    <s:Group id="contentGroup" left="10" right="10" top="10" bottom="10" minWidth="0" minHeight="0">
        <s:layout>
            <s:BasicLayout>
            </s:BasicLayout>
        </s:layout>
    </s:Group>

</s:Skin>

and in my main, I put two section components into a VGroup that is in a panel (here is the VGroup content):

<component:GlassSectionComponent title="titi" width="100%" height="100%" skinClass="skin.GlassSectionContainerSkin">
                                        <s:HGroup left="7" right="3" top="10" bottom="5" width="100%" height="100%">
                                            <s:Button id="mybutn0" label="click!/>
                                            <s:Button id="mybutn1" label="click!/>
                                        </s:HGroup>
                                    </component:GlassSectionComponent>
<component:GlassSectionComponent title="toto" width="90%" height="90%" skinClass="skin.GlassSectionContainerSkin">
                                        <s:VGroup left="7" right="3" top="10" bottom="5" width="100%" height="100%">
                                            <s:Button id="mybutn2" label="click!/>
                                            <s:Button id="mybutn3" label="click!/>
                                        </s:VGroup>
                                    </component:GlassSectionComponent>

You can see that in my skin I put a function called "fitContent" so that the skin fits the size of the contentGroup. But even if it works perfectly for a VGroup, the section that contains a HGroup resizes step by step when my mouse is over the buttons. I suspect a problem in my "fitContent" function but I'm not sure.

1

1 Answers

1
votes

Whenever anything gets added to the container (or its children, or grandchildren), your fitContent will be called. Sometimes when you set minWidth and minHeight and then invalidateSize, you can get into a loop where things creep in size...I haven't been able to identify the exact place this happens.

Here's an idea: SkinnableContainer's default size is large enough to fit the children. So, look at BorderContainer and see where it overrides that, and override it back. Or, just start with SkinnableContainer. Panel already has a title bar and its default size is large enough to fit its children. Why not just give it a custom skin, if the way it displays the title isn't exactly what you want?