I have multiple components one nested into another. Like one <s:Group /> is child of other <s:Group /> which is child of another <s:Group /> and so on. The problem is that different components gets disabled depending on different conditions. It might happen that all components are disabled at once, due to which the innermost component loses its visibility.
I am posting a sample code here depicting my situation.
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication 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>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:Group horizontalCenter="0" verticalCenter="0" >
<s:Group enabled="false">
<s:Group enabled="false">
<s:Group enabled="false" horizontalCenter="0" verticalCenter="0">
<mx:Canvas disabledOverlayAlpha="1" width="{tlGroup.width}" height="{tlGroup.height}">
<s:TileGroup id="tlGroup" enabled="false" >
<mx:CheckBox selected="true" enabled="true"/>
<mx:CheckBox enabled="true" />
</s:TileGroup>
</mx:Canvas>
</s:Group>
</s:Group>
</s:Group>
</s:Group>
</s:WindowedApplication>
Further I cannot use disabledAlpha="" as I am using Halo theme in additional compiler arguments(-theme=${flexlib}/themes/Halo/halo.swc).
This seems like a good case for using Flex states.
Add to your MXML file the code:
<s:states>
<s:State name="my_state_1" />
<s:State name="my_state_2" />
</s:states>
And then add to your groups and/or elements includeIn="my_state_1" and enabled.my_state_2="true" etc.
Related
I have a transition setup on my Spark component. One of the changes from state 1 to state 2 is the change in height. The value was getting applied immediately. Here is my code:
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
height="200" height.state2="400">
<s:states>
<s:State name="state1"/>
<s:State name="state2"/>
</s:states>
<s:transitions>
<s:Transition fromState="state1" toState="state2" >
<s:Sequence duration="2000" >
<s:Rotate3D target="{this}"
angleYFrom="0" angleYTo="90"
startDelay="0"
suspendBackgroundProcessing="true"
autoCenterTransform="true" />
<s:SetAction target="{this}" property="height"/>
<s:Rotate3D target="{this}"
angleYFrom="-90" angleYTo="0"
startDelay="0"
suspendBackgroundProcessing="true"
autoCenterTransform="true" />
</s:Sequence>
</s:Transition>
</s:transitions>
<s:Rect width="100%" height="100%" >
<s:fill>
<s:SolidColor color="#ff0000"/>
</s:fill>
</s:Rect>
</s:Group>
And then in my main application:
<?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"
minWidth="955" minHeight="600" xmlns:local="*"
>
<local:MyGroup id="group" verticalCenter="0" horizontalCenter="0" width="400"/>
<s:Button label="Change states" click="group.currentState=group.currentState=='state1'?'state2':'state1';"/>
</s:Application>
The solution is to use the explicitHeight property rather than height. This is because height is a special property symbol that Flex uses.
From the SetProperty PSEUDONYMS property:
/**
* #private
* This is a table of pseudonyms.
* Whenever the property being overridden is found in this table,
* the pseudonym is saved/restored instead.
*/
private static const PSEUDONYMS:Object =
{
width: "explicitWidth",
height: "explicitHeight",
currentState: "currentStateDeferred"
};
So if you've set the height then it's actually explicitHeight that is set. Keep in mind another related property called RELATED_PROPERTIES. It contains additional data on percent width and height and explicit width and height information.
For more information see mx.states.SetProperty.
To solve the problem in this case we change this:
<s:SetAction target="{this}" property="height"/>
To this:
<s:SetAction target="{this}" property="explicitHeight"/>
I have a small problem with rollover effects. First time after loading everything's fine. But after clicking the button twice (= going to studyState and then coming back to Sate1) the rollover effect on the bordercontainer stops working.
I don't have a clue what the reason could be. Please give me a hint.
<?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" minWidth="955" minHeight="600">
<fx:Declarations>
<s:AnimateColor id="animateColorON" colorPropertyName="backgroundColor" colorFrom="#FFFFFF" colorTo="#e7eae4" duration="300"/>
<s:AnimateColor id="animateColorOFF" colorPropertyName="backgroundColor" colorFrom="#e7eae4" colorTo="#FFFFFF" duration="600"/>
</fx:Declarations>
<s:transitions>
<s:Transition id="t1" autoReverse="true">
<s:CrossFade
target="{this}"
duration="1500" />
</s:Transition>
</s:transitions>
<s:states>
<s:State name="State1" />
<s:State name="studyState" />
</s:states>
<s:VGroup id="globalGroup" includeIn="State1" width="100%">
<s:Button label="State1 to studyState" click="this.currentState = 'studyState'" />
<s:BorderContainer width="100%" height="30" cornerRadius="4" borderVisible="false" buttonMode="true" rollOverEffect="animateColorON" rollOutEffect="animateColorOFF">
<s:HGroup width="100%" height="30" verticalAlign="middle" paddingLeft="5" paddingRight="5">
<s:Label id="p_dob_label" text="text" width="55%"/>
<s:Label id="p_dob_value" text="text" width="40%" verticalAlign="top" textAlign="right" color="#8DA576"/>
</s:HGroup>
</s:BorderContainer>
</s:VGroup>
<s:VGroup id="studyGroup" includeIn="studyState" width="100%">
<s:Button label="studyState to State1" click="this.currentState = 'State1'" />
</s:VGroup>
</s:Application>
Here is a fix. add an event listener for when the state changes. I use the currentStateChangeevent:
<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" minWidth="955" minHeight="600" currentStateChange="application1_currentStateChangeHandler(event)">
In the listener, manually set the rollOverEffect and rollOutEffect effects:
<fx:Script>
<![CDATA[
import mx.events.StateChangeEvent;
protected function application1_currentStateChangeHandler(event:StateChangeEvent):void
{
// TODO Auto-generated method stub
if(bc){
bc.setStyle('rollOverEffect',animateColorON);
bc.setStyle('rollOutEffect',animateColorOFF);
}
}
]]>
</fx:Script>
Be sure to give the BorderContainer an ID. I used bc:
<s:BorderContainer id="bc" width="100%" height="30" cornerRadius="4" borderVisible="false" buttonMode="true" rollOverEffect="animateColorON" rollOutEffect="animateColorOFF" >
I'm not sure why those effects are lost. My best theory is that this has something to do with how the ActionScript is generated behind the scenes. Even though the rollOverEffect and rollOutEffect appear to be properties on the component, they are actually implemented behind the scenes as styles. I bet, for some reason, when switching states the 'effect' styles are not reset. You'd have to look at the generated ActionScript to know for sure, though.
How on earth do you put a simple gradient with css in the buttons of a buttonbar?
I've been looking everywhere and I'm not interested in skinning at all it seems weird having all that dirty code to have just a simple gradient.
This is my css
.my_ButtonBar{
buttonStyleName: "buttonBarButton";
firstButtonStyleName: "firstButtonBarButton";
lastButtonStyleName: "lastButtonBarButton";
}
.buttonBarButton
{
fillColors: red, red;
}
And this is my mxml
<s:ButtonBar dataProvider="{viewstack}" width="200" top="0" left="0" styleName="main_ButtonBar">
<s:layout>
<s:TileLayout columnWidth="200" rowHeight="50"
horizontalGap="-1" verticalGap="-1" />
</s:layout>
</s:ButtonBar>
After user700284's response I created a new skinclass based on the buttonbar class.
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark"
alpha.disabled="0.5">
<fx:Metadata>
<![CDATA[
/**
* #copy spark.skins.spark.ApplicationSkin#hostComponent
*/
[HostComponent("spark.components.ButtonBar")]
]]>
</fx:Metadata>
<s:states>
<s:State name="normal" />
<s:State name="disabled" />
</s:states>
<fx:Declarations>
<fx:Component id="firstButton">
<s:ButtonBarButton skinClass="spark.skins.spark.ButtonBarFirstButtonSkin" />
</fx:Component>
<fx:Component id="middleButton" >
<s:ButtonBarButton skinClass="spark.skins.spark.ButtonBarMiddleButtonSkin" />
</fx:Component>
<fx:Component id="lastButton" >
<s:ButtonBarButton skinClass="spark.skins.spark.ButtonBarLastButtonSkin" />
</fx:Component>
</fx:Declarations>
<s:DataGroup id="dataGroup" width="100%" height="100%">
<s:layout>
<s:TileLayout columnWidth="200" rowHeight="50"
horizontalGap="-1" verticalGap="-1" />
</s:layout>
</s:DataGroup>
</s:Skin>
If I add a rect fill it will fill up the entire buttonbar instead of each button individually. How can I just put a simple gradient on the buttons?????
I do not think you will be able to control the fillColors through a CSS because spark Button does not support fillColors style.Check the following link:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/spark/components/Button.html#commonstyleSummary
So you might have to resort to creating skins for buttons. :(
There is a Spark style 'chromeColor' that modifies the default colors.
FTQuest
Below is a very simple example, randomly, if I click the step2 button the state will change but the Step 2 panel will not be there.
I suspect the children of the state are not getting created for some reason, which is why I set the itemCreationPolicy to "immediate", but it makes no difference
This is catastrophic for the application because the user is left in limbo and is forced to refresh
Any ideas, please?
<s:BorderContainer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
creationPolicy="all" currentState="step1">
<s:states>
<s:State name="step1"/>
<s:State name="step2"/>
</s:states>
<s:BorderContainer includeIn="step1" itemCreationPolicy="immediate">
<s:Panel title="Step 1"/>
</s:BorderContainer>
<s:BorderContainer includeIn="step2" itemCreationPolicy="immediate">
<s:Panel title="Step 2"/>
</s:BorderContainer>
<s:Button title="step1" click="{this.setCurrentState('step1',true)}"/>
<s:Button title="step2" click="{this.setCurrentState('step2',true)}"/>
</s:BorderContainer>
I've just tested it with Flex SDK 4.1 and it works without changing the creation policy. Clicking "step 2" successfully changes the state.
BTW: You don't need the curly braces in you click event handler...
<?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" currentState="step1">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<s:states>
<s:State name="step1"/>
<s:State name="step2"/>
</s:states>
<s:BorderContainer includeIn="step1">
<s:Panel title="Step 1"/>
</s:BorderContainer>
<s:BorderContainer includeIn="step2">
<s:Panel title="Step 2"/>
</s:BorderContainer>
<s:Button label="step1" click="setCurrentState('step1', true)"/>
<s:Button label="step2" click="setCurrentState('step2', true)"/>
</s:Application>
Seems that you use old / pre-release version of Flex 4 SDK. It might be a good idea to update to 4.1.0 - last stable version.
P.S: Writing this.setCurrentState('step1',true) is not the best idea. I suggest to use currentState = 'step1' - it is the official way of state changing.
Using FB4, I want to change the height of an open spark DropDownList. By default, it shows up to 6 items before scrolling. My dropdownlist contains 7 items, so I want to change the height of the open dropdown list to fit all 7 items without scrolling. As a workaround, I've changed the font size of the items so that they are smaller and all 7 fit, but the smaller font doesn't look good. Is there a way to change this height? I'm rather new to Flash, so if it's a complicated solution, please be detailed :-).
Isn't it easier if you use the property requestedRowCount of the verticalLayout?
<s:DropDownList dataProvider="{myDataProvider}">
<s:layout>
<s:VerticalLayout requestedRowCount="10"/>
</s:layout>
</s:DropDownList>
The issue is, in Flex 4, the DropDownListSkin has defined maxHeight="134" for the default skin you are probably using. That forces the scrollbar to appear if the objects stretch beyond that height. All you need to do is copy/paste their DropDownListSkin code into a custom skin, and apply that to your DropDownList via CSS:
VariableHeightDropDownListSkin
<?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"
alpha.disabled=".5">
<!-- host component -->
<fx:Metadata>
<![CDATA[
/**
* #copy spark.skins.spark.ApplicationSkin#hostComponent
*/
[HostComponent("spark.components.DropDownList")]
]]>
</fx:Metadata>
<s:states>
<s:State name="normal" />
<s:State name="open" />
<s:State name="disabled" />
</s:states>
<s:PopUpAnchor id="popUp" displayPopUp.normal="false" displayPopUp.open="true" includeIn="open"
left="0" right="0" top="0" bottom="0" itemDestructionPolicy="auto"
popUpPosition="below" popUpWidthMatchesAnchorWidth="true">
<!-- removed maxHeight! -->
<s:Group id="dropDown" minHeight="22">
<!-- border/fill -->
<s:Rect left="0" right="0" top="0" bottom="0">
<s:stroke>
<s:SolidColorStroke color="0x5380D0" />
</s:stroke>
<s:fill>
<s:SolidColor color="0xFFFFFF" />
</s:fill>
</s:Rect>
<s:Scroller left="0" top="0" right="0" bottom="0" focusEnabled="false" minViewportInset="1">
<s:DataGroup id="dataGroup" itemRenderer="spark.skins.spark.DefaultItemRenderer">
<s:layout>
<s:VerticalLayout gap="0" horizontalAlign="contentJustify"/>
</s:layout>
</s:DataGroup>
</s:Scroller>
<s:filters>
<s:DropShadowFilter blurX="20" blurY="20" distance="7" angle="90" alpha="0.45" color="0x6087CC" />
</s:filters>
</s:Group>
</s:PopUpAnchor>
<s:Button id="openButton" left="0" right="0" top="0" bottom="0" focusEnabled="false"
skinClass="spark.skins.spark.DropDownListButtonSkin" />
<s:Label id="labelDisplay" verticalAlign="middle" lineBreak="explicit"
mouseEnabled="false" mouseChildren="false"
left="7" right="30" top="2" bottom="2" width="75" verticalCenter="1" />
</s:Skin>
Sample Application
<?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 mx "library://ns.adobe.com/flex/mx";
#namespace s "library://ns.adobe.com/flex/spark";
s|DropDownList
{
skinClass: ClassReference("VariableHeightDropDownListSkin");
}
</fx:Style>
<s:DropDownList labelField="name" horizontalCenter="0" verticalCenter="0">
<s:layout>
<s:VerticalLayout requestedRowCount="7"/>
</s:layout>
<s:dataProvider>
<mx:ArrayCollection>
<fx:Object name="one"/>
<fx:Object name="two"/>
<fx:Object name="three"/>
<fx:Object name="four"/>
<fx:Object name="five"/>
<fx:Object name="six"/>
<fx:Object name="seven"/>
</mx:ArrayCollection>
</s:dataProvider>
</s:DropDownList>
</s:Application>
Let me know if that helps,
Lance
viatropos answer will work, however you should try and avoid overriding an entire skin as much as possible.
In this case, you will notice that in viatropos's VariableHeightDropDownListSkin code that the Group where he removed the maxHeight attribute, there is also an "id" specified.
Now look at the documentation for DropDownList and you will notice in the SkinParts section that there is a "dropDown" skin part. This is actually a property of DropDownList.
So instead of overriding the skin, you can simply use actionscript (I use UIComponent.DEFAULT_MAX_HEIGHT here, but you can use whichever you wish):
(MyDropDownList.dropDown as UIComponent).maxHeight = UIComponent.DEFAULT_MAX_HEIGHT;
Unfortunately, this is a lot more complicated in Flex 4 than it was in Flex 3:
You should be able to define a layout for the DropDownList with a higher requestedRowCount (details here), but for > 6 rows you need to do more work (Flex issue SDK-25364).
in FB3 it's rowCount cause the dropdown is a descendant of a list control. FB4 is probably similar.
myDropdown.rowCount = 7;
I usually use something more like
myDropdown.rowCount = myDataProvider.lenght();