Flex 4 state transition Move effect in a VGroup - apache-flex

I am trying to create a nice state transition where I have 2 containers (in the example below I have used panels).
When the state changes, I want to fade away the upper panel, then move the lower panel to the top of the screen, and below that I want to fade in a new 'lower' panel.
In the code below, the fades are working fine, but the panel doesn't move to the top of the box, it just goes to it's new position without a transition.
Also the 'reverse' transition doesn't happen at all. I tried to set autoReverse to true, and I also tried to build an opposite transition, both no result, there was no transition.
When I replace the VGroup (in which it all happens) for VBox, I get a slightly better result, the transition works in one way. The reverse transition still doesn't work at all.
<?xml version="1.0" encoding="utf-8"?>
<fx:Script>
<![CDATA[
private function switchMode():void
{
if (currentState == "up")
currentState = "down";
else
currentState = "up";
}
]]>
</fx:Script>
<s:states>
<s:State name="up" />
<s:State name="down" />
</s:states>
<s:transitions>
<s:Transition fromState="up" toState="down">
<s:Sequence>
<s:Fade target="{upperGrid}" />
<s:RemoveAction target="{upperGrid}" />
<s:Move target="{panel1}" />
<s:AddAction target="{lowerGrid}" />
<s:Fade target="{lowerGrid}" />
</s:Sequence>
</s:Transition>
<s:Transition fromState="down" toState="up">
<s:Sequence>
<s:Fade target="{lowerGrid}" />
<s:RemoveAction target="{lowerGrid}" />
<s:Move target="{panel1}" />
<s:AddAction target="{upperGrid}" />
<s:Fade target="{upperGrid}" />
</s:Sequence>
</s:Transition>
</s:transitions>
<s:VGroup width="100%" height="100%" top="10" left="10" right="10" bottom="10">
<s:Panel id="upperGrid" width="100%" height="100%" includeIn="up" title="upper panel" />
<s:Panel id="panel1" width="100%" title="Panel">
<s:Button label="Switch mode" click="switchMode()" />
</s:Panel>
<s:Panel id="lowerGrid" width="100%" height="100%" includeIn="down" title="lower panel" />
</s:VGroup>
When I get rid of the VGroup or VBox, and use absolute positions, the transitions work fine:
<s:Panel id="upperGrid" left="10" right="10" top="10" bottom="{panel1.height + 20}" includeIn="up" title="upper panel" />
<s:Panel id="panel1" left="10" right="10" top.up="{upperGrid.height + 20}" top.down="10" title="Panel">
<s:Button label="Switch mode" click="switchMode()" />
</s:Panel>
<s:Panel id="lowerGrid" left="10" right="10" top="{panel1.height + 20}" bottom="10" includeIn="down" title="lower panel" />
Should you always use absolute positioning if you want these kind of moving transitions or is it possible to use these transitions in a VGroup or VBox combined with includeIn and excludeFrom properties? And if so, how could I correct that in the example above?

The problem is that you're using a container that is meant to 'layout' it's children. You could try to create your own layout that could know when it's children are currently in an effect and not touch them until they're done, or use an absolutely positioned layout container (like Group) instead.

Related

Flex button skins return to default

I have a problem which involves skinned buttons returning to their default skins after certain actions occur in my application. Below I have included a partial screenshot where you can observe the problem.
The left button is returned to its default skin after it was clicked (the click triggers a state transition). The right button is the default skinned button. Note that my mouse is neither over nor pressing the left button.
The code for the Button Skin is as follows:
<?xml version="1.0" encoding="utf-8"?>
<fx:Metadata>
<![CDATA[
[HostComponent("spark.components.Button")]
]]>
</fx:Metadata>
<fx:Script fb:purpose="styling">
<![CDATA[
import spark.components.Group;
static private const exclusions:Array = ["labelDisplay"];
override public function get colorizeExclusions():Array {return exclusions;}
override protected function initializationComplete():void
{
useChromeColor = true;
super.initializationComplete();
}
]]>
</fx:Script>
<s:states>
<s:State name="up" />
<s:State name="over" />
<s:State name="down" />
<s:State name="disabled" />
</s:states>
<s:Rect id="fill" left="1" right="1" top="1" bottom="1" radiusX="2">
<s:fill>
<s:LinearGradient rotation="270">
<s:GradientEntry color.down="#545454"
color.over="#444444"
color="#343434"
alpha="0.95"/>
<s:GradientEntry color.down="#767676"
color.over="#666666"
color="#565656"
alpha="0.95"/>
</s:LinearGradient>
</s:fill>
</s:Rect>
<s:Rect id="border" left="0" right="0" top="0" bottom="0" width="69" height="20" radiusX="3">
<s:stroke>
<s:SolidColorStroke id="borderStroke" weight="1" color="#343434" caps="round" joints="round" />
</s:stroke>
</s:Rect>
<s:Label id="labelDisplay"
textAlign="center" verticalAlign="middle" maxDisplayedLines="1" fontSize="12"
left="10" right="10" verticalCenter="0"
color="#FFFFFF" fontFamily="SegoeUI">
</s:Label>
Here's the code for the transition that is causing the problem:
<s:Transition fromState="State0" toState="State1">
<s:Sequence targets="{[contacts_nocontacts, contacts_list, button_contacts, button_add, button_delete, ac_vgroup]}">
<s:Parallel>
<s:Fade target="{contacts_nocontacts}" alphaFrom="1" alphaTo="0" duration="200" />
<s:Fade target="{contacts_list}" alphaFrom="1" alphaTo="0" duration="200" />
<s:Fade target="{button_add}" alphaFrom="1" alphaTo="0" duration="200" />
<s:Fade target="{button_delete}" alphaFrom="1" alphaTo="0" duration="200" />
</s:Parallel>
<s:RemoveAction targets="{[contacts_nocontacts, contacts_list, button_add, button_delete]}" />
<s:AddAction targets="{[button_contacts, ac_vgroup]}" />
<s:Parallel>
<s:Fade target="{button_contacts}" alphaFrom="0" alphaTo="1" duration="300" />
<s:Fade target="{ac_vgroup}" alphaFrom="0" alphaTo="1" duration="300" />
</s:Parallel>
</s:Sequence>
</s:Transition>
It looks like the skin is being set to the spark.skins.spark.DefaultButtonSkin (not to be confused with the normal Button skin - spark.skins.spark.ButtonSkin). This happens when you set emphasized="true" on the Button or that button is being used as a default Button in a Form.
See this thread for an example of how to customize the emphasized skin: http://forums.adobe.com/message/3811868
The problem is that the Skin is reset when focus is lost on a button that is set as Default button. It's standard behaviour, a quick fix can be found beneath (it's the same solution as the one Steven pointed out, but It's easier to have it on this actual page)
s|Button.emphasized {
skinClass: ClassReference("MyNewButtonSkin");
}
Just attach the same button skinClass on the emphasized style property of your button. The best way to do this the quickest is to do it with above CSS. On this way you can target all the buttons at once!

Why is this Flex 4 Transition not working?

I have a test application here which was made using the following code:
<fx:Script>
<![CDATA[
public function comboBoxHandler():void{
var selectedItem:String = showComboBox.selectedItem;
if(selectedItem == "All results"){
currentState = "default";
return;
}else if(selectedItem == "Only results within tags"){
currentState = "tagInput";
return;
}
}
]]>
</fx:Script>
<s:states>
<s:State name="default"/>
<s:State name="tagInput"/>
</s:states>
<s:transitions>
<s:Transition id="showTagTextInput" fromState="default" toState="tagInput">
<s:Sequence id="t1p1" targets="{[tagsLabel,tagsTextInput,GoButton]}">
<s:Move duration="700"/>
<s:Fade duration="400"/>
</s:Sequence>
</s:Transition>
<s:Transition id="hideTagTextInput" fromState="tagInput" toState="default">
<s:Sequence id="t2p1" targets="{[tagsLabel,tagsTextInput,GoButton]}" >
<s:Fade duration="400"/>
<s:Move duration="700"/>
</s:Sequence>
</s:Transition>
</s:transitions>
<s:Label x="136" y="13" width="120" height="34" fontFamily="Arial" fontSize="15"
text="Lessons
Learnt" textAlign="center"/>
<s:Group id="group" width="100%" height="100%"
x.default="0" y.default="55" width.default="400" height.default="231"
y.tagInput="55" height.tagInput="256">
<s:Label x="45" y="38" width="50" height="22" text="Search" textAlign="center"
verticalAlign="middle"/>
<s:TextInput x="103" y="38" width="193"
useHandCursor.tagInput="false"/>
<s:Label x="45" y="89" width="51" height="22" text="Show" textAlign="center"
verticalAlign="middle"/>
<s:Button id="GoButton" x="253" y="137" width="43" label="Go" useHandCursor="true"
buttonMode="true" mouseChildren="false"
x.tagInput="254" y.tagInput="188"/>
<s:DropDownList id="showComboBox" x="104" y="89" width="192" change="comboBoxHandler();"
selectedIndex="0">
<s:ArrayCollection>
<fx:String>All results</fx:String>
<fx:String>Only results within tags</fx:String>
</s:ArrayCollection>
</s:DropDownList>
<s:Label id="tagsLabel" includeIn="tagInput" x="104" y="146" width="61" height="20" text="Tags"
textAlign="center" verticalAlign="middle"/>
<s:TextInput id="tagsTextInput" includeIn="tagInput" x="173" y="146" width="123"/>
</s:Group>
You can check, by clicking the link I gave, that this app performs some basic transition effect when you select different options from the DropDownBox.
The first (show) transition doesn't work so well, but the second (hide) transition does.
Does anyone know how to fix that? In the first transition, I would like the button to slide down first, only after that should the text input fade In. Why isn't this working?
Thanks in advance.
It is better to point particular effect target rather that pointing all the targets in <s:Sequence />. So place targets to <s:Move /> and <s:Fade />. Also you can perform additional transitions tuning by placing <s:AddAction /> and <s:RemoveAction /> with corresponding targets to point a place within sequence where transition should invoke includeIn and excludeFrom states declarations.
So these transitions works fine with your code:
<s:transitions>
<s:Transition fromState="default" id="showTagTextInput" toState="tagInput">
<s:Sequence id="t1p1">
<s:Move duration="700" targets="{[GoButton]}" />
<s:AddAction targets="{[tagsLabel,tagsTextInput]}" />
<s:Fade duration="400" targets="{[tagsLabel,tagsTextInput]}" />
</s:Sequence>
</s:Transition>
<s:Transition fromState="tagInput" id="hideTagTextInput" toState="default">
<s:Sequence id="t2p1">
<s:Fade duration="400" targets="{[tagsLabel,tagsTextInput]}" />
<s:RemoveAction targets="{[tagsLabel,tagsTextInput]}" />
<s:Move duration="700" targets="{[GoButton]}" />
</s:Sequence>
</s:Transition>
</s:transitions>
I would imagine it's because your tag input is only being included in the tagInput state, but the alpha is 100% and there's no transition between the states. Try this:
<s:Label id="tagsLabel" alpha.default="0" alpha.tagInput="100" x="104" y="146" width="61" height="20" text="Tags" textAlign="center" verticalAlign="middle"/>
<s:TextInput id="tagsTextInput" alpha.default="0" alpha.tagInput="100" x="173" y="146" width="123"/>
You might also want to set visible to false during 'default' state. Also, what Constantiner said is true.

In Flex 4, state transition doesn't resize in both directions (v2)

I already had another question on this issue which was successfully resolved. But now, with a slightly different example, I'm stuck again.
I have two states. When I switch from A to B, it resizes correctly, but when I switch from B back to A it happens without the smooth resize transition. What am I doing wrong?
Here's my code:
<fx:Script>
<![CDATA[
protected function rollOverHandler(event:MouseEvent):void
{
this.currentState = "AB";
}
protected function rollOutHandler(event:MouseEvent):void
{
this.currentState = "A";
}
]]>
</fx:Script>
<fx:Declarations>
</fx:Declarations>
<s:states>
<s:State name="A" />
<s:State name="AB" />
</s:states>
<s:transitions>
<s:Transition fromState="A" toState="AB" autoReverse="true">
<s:Parallel>
<s:AddAction target="{controls}"/>
<s:Resize duration="500" target="{controls}" heightFrom="0" />
</s:Parallel>
</s:Transition>
<s:Transition fromState="AB" toState="A" autoReverse="true">
<s:Parallel>
<s:Resize duration="500" target="{controls}" heightTo="0" />
<s:RemoveAction target="{controls}"/>
</s:Parallel>
</s:Transition>
</s:transitions>
<s:BorderContainer width="300"
backgroundColor="#eeeeee"
borderVisible="false"
minHeight="0">
<s:layout>
<s:VerticalLayout gap="0"/>
</s:layout>
<s:VGroup id="data">
<s:Label text="A" fontSize="40" />
</s:VGroup>
<s:VGroup id="controls"
clipAndEnableScrolling="true"
itemCreationPolicy="immediate"
includeIn="AB">
<s:Label text="B" fontSize="40" />
</s:VGroup>
</s:BorderContainer>
</s:HGroup>
Thanks in advance,
Nuno
You need to use a Sequence instead of a Parallel.

States Transition when elements are removed

I would like to write a transition where all the elements from State1 rotate around Y axis and then show elements from State2
This s illustrated in the dummy code below (just imagine Label 1 is a Group).
<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">
<s:states>
<s:State name="State1"/>
<s:State name="State2"/>
</s:states>
<s:transitions>
<s:Transition fromState="*" toState="State2" autoReverse="true">
<s:Rotate3D target="{label2}" angleYFrom="-90" angleYTo="0" autoCenterTransform="true" duration="1000"/>
</s:Transition>
</s:transitions>
<fx:Declarations>
<s:Rotate3D id="phaseOut" target="{label1}" angleYFrom="0" angleYTo="90" autoCenterTransform="true" duration="1000" effectEnd="currentState='State2'" />
</fx:Declarations>
<s:Label id="label1" includeIn="State1" text="This is state 1" horizontalCenter="0" verticalCenter="0"/>
<s:Label id="label2" includeIn="State2" text="This is state 2" horizontalCenter="0" verticalCenter="0"/>
<s:Button label="Change" horizontalCenter="0" verticalCenter="30" click.State1="phaseOut.play()" click.State2="currentState='State1'"/>
</s:WindowedApplication>
My first problem is when the state transition is invoked, all elements from State1 are already gone, hence I have to split the transition in two hacks (see "phaseOut")
This seems really poor since I am essentially rewritting the transition mechanism.
Q1: Is there a "clean" way to transition elements that do not belong to State2 ?
The second problem is when you revert back to State 1, elements have been rotated.
Q2: Is there such a thing as "autoReverse" for animations?
Thanks for your time!
Instead of doing two transitions, you can add the 'remove' filter to isolate an effect just on items being removed and use the RemoveChildAction to let the transition know when to execute the action to remove the items.
Info on RemoveChildAction:
http://livedocs.adobe.com/flex/3/langref/mx/effects/RemoveChildAction.html
Info on filters:
http://livedocs.adobe.com/flex/3/langref/mx/effects/Effect.html#filter
Effects have a reverse method to play it in reverse:
http://livedocs.adobe.com/flex/3/langref/mx/effects/Effect.html#reverse%28%29
Although I've heard mixed results from people about how successful it is.
Using viewstacks seems to do the trick nicely:
<?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:Declarations>
<s:Rotate3D id="phaseOut" angleYFrom="0" angleYTo="90" duration="500" autoCenterTransform="true" />
<s:Rotate3D id="phaseIn" angleYFrom="-90" angleYTo="0" duration="500" autoCenterTransform="true" startDelay="500" />
</fx:Declarations>
<mx:ViewStack id="viewstack1" width="200" height="200" horizontalCenter="0" verticalCenter="0">
<s:NavigatorContent label="View 1" width="100%" height="100%" hideEffect="{phaseOut}" showEffect="{phaseIn}" >
<s:Label id="label1" text="This is state 1" horizontalCenter="0" verticalCenter="0"/>
</s:NavigatorContent>
<s:NavigatorContent label="View 2" width="100%" height="100%" hideEffect="{phaseOut}" showEffect="{phaseIn}">
<s:Label id="label2" text="This is state 2" horizontalCenter="0" verticalCenter="0"/>
</s:NavigatorContent>
</mx:ViewStack>
<s:Button label="Toggle" click="viewstack1.selectedIndex=(viewstack1.selectedIndex==0?1:0)" horizontalCenter="0" top="10"/>
</s:Application>
The code is neat and the effect is exactely as expected

flex transition effects works on 2nd and after transition, but not on very first transition

i have a flex app that transitions between 2 states with the toggle of a button. my issue is that the effect of fading only seems to work on the 2nd transition and after. However, for my first transition... going from State1 to studyState... there is no fade effect whatsoever, in fact the components in state1 disappear completely (the footer fills the empty gap where the "body" use to be) and then the flex recreates the studyState (without any fade refilling the "body" with components only in studyState).
After this first transition however, going between studyState and State1 working COMPLETELY fine.. why does this happen and how can i make it so that crossfade works STARTING FROM THE VERY FIRST TRANSITION? please help!
<s:transitions>
<s:Transition id="t1" autoReverse="true">
<s:CrossFade
target="{holder}"
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%">stuff</Vgroup>
<s:VGroup id="studyGroup" includeIn="studyState" width="100%">stuff</Vgroup>
What is wrong about the state transition? Can you provide a full code sample?
This code segment, basically, works as I would have expected:
<?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">
<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:VGroup>
<s:VGroup id="studyGroup" includeIn="studyState" width="100%">
<s:Button label="studyState to State1" click="this.currentState = 'State1'" />
</s:VGroup>
</s:Application>

Resources