I would like to create a component that apply a resize effect when the it is visible:
I did this:
<s:Panel id="loginPanel" title="Connect" creationCompleteEffect="customResize"
showEffect="customResize" hideEffect="fadeOut"
width="400" height="300" includeIn="login">
with:
<fx:Declarations>
<!-- Effects declaration -->
<s:Fade id="fadeIn" alphaFrom="0.0" alphaTo="1.0" duration="500"/>
<s:Fade id="fadeOut" alphaFrom="1.0" alphaTo="0.0" duration="500"/>
<s:Animate id="customResize" duration="1000">
<s:SimpleMotionPath property="percentWidth" valueFrom="0" valueTo="100"/>
<s:SimpleMotionPath property="percentHeight" valueFrom="0" valueTo="100"/>
</s:Animate>
</fx:Declarations>
The problem is that when the component is displayed for the first time, the effect is correctly played but when the state change for example from "login" to "working" then back to "login", the effect isn't played anymore.
I thought that a visibility event would have been dispatched and the showEffect applied but it seems that the state changes don't work like I was expecting.
How can I apply the effect each time the component is visible?
are you sure the states are toggling the visible property?
Try to force Visible property to change:
<s:Fade id="fadeIn" alphaFrom="0.0" alphaTo="1.0" duration="500" effectStart="loginPanel.visible = true"/>
<s:Fade id="fadeOut" alphaFrom="1.0" alphaTo="0.0" duration="500" effectEnd="loginPanel.visible = false"/>
Related
In Flex 3 you could do a glow effect like so:
<mx:Glow id="glowImage" duration="250"
alphaFrom="0" alphaTo="1"
blurXFrom="0.0" blurXTo="3.0"
blurYFrom="0.0" blurYTo="3.0" strength="2"
color="0xcc0000" target="{this}"/>
<mx:Glow id="unglowImage" duration="250"
alphaFrom="1" alphaTo="0"
blurXFrom="3.0" blurXTo="0.0"
blurYFrom="3.0" blurYTo="0.0" strength="2"
color="0xaaaaaa" target="{this}"/>
And the MXML:
<mx:Image rollOverEffect="{glowImage}" rollOutEffect="{unglowImage}"/>
In Flex 4 we are supposed to use the AnimateFilter with a GlowFilter (recommended by Adobe). Here's what I've come up with:
<s:AnimateFilter id="glowAnimation"
target="{this}"
duration="250"
>
<s:bitmapFilter>
<s:GlowFilter color="#ff0000" strength="3" quality="3" />
</s:bitmapFilter>
<s:motionPaths>
<s:SimpleMotionPath valueFrom="0" valueTo="4" property="blurX"/>
<s:SimpleMotionPath valueFrom="0" valueTo="4" property="blurY"/>
</s:motionPaths>
</s:AnimateFilter>
And the MXML:
<mx:Image rollOverEffect="{glowAnimation}" rollOutEffect="{unglowImage}"/>
The problem is that this animates once and then the effect is removed where as the mx effect applies the filter and keeps it applied.
~~~ UPDATE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
RIAStar's answer is right and I want to add the reason why from this video I just stumbled upon [1]. It describes the differences between Animate and AnimateFilter. AnimateFilter is transient. It applies the filter and when it's done it removes it. Animate applies the values to the target permanently.
We also should be aware that in Flex 4 not all effects support triggers.
From the AnimateInstance class:
override public function startEffect():void
{
// This override removes EffectManager.effectStarted() to avoid use of
// mx_internal. New effects are not currently triggerable, so
// this should not matter
}
What this means is that we cannot rely on rollOverEffect to trigger the effect bound to it. We must call effect.play() on the rollOver event.
So that means when we use the Animate class we also need to change this:
<s:Image rollOverEffect="{glowImage}" rollOutEffect="{unglowImage}"/>
to this:
<s:Image rollOver="glowImage.play()" rollOut="unglowImage.play()"/>
Note when using multiple related effects it is best practice to call end() on a playing effect before calling play() on it's related effect.
Also, note when using a single effect, as in the answer, reverse it rather than end it like so glowAnimation.play(null, true).
<s:Image rollOver="rollOverAnimation.play()" rollOut="rollOverAnimation.play(null, true)"/>
I don't know about AnimateFilter, but this solution using a simple Animate effect should work nicely:
<s:Animate id="glowAnimation" target="{glow}" duration="250">
<s:motionPaths>
<s:SimpleMotionPath valueFrom="0" valueTo="10" property="blurX"/>
<s:SimpleMotionPath valueFrom="0" valueTo="10" property="blurY"/>
</s:motionPaths>
</s:Animate>
<s:Image rollOver="glowAnimation.play()"
rollOut="glowAnimation.play(null, true)">
<s:filters>
<s:GlowFilter id="glow" blurX="0" blurY="0" />
</s:filters>
</s:Image>
Note that I set the initial values of blurX and blurY to 0. This is necessary because otherwise it will display the default 4 as long as you don't roll over the image.
I use transitions for effect switching within SparkSkin. For bluring a skinned item under cursor:
<!-- states -->
<s:states>
<s:State name="up" />
<s:State name="over" />
<s:State name="down" />
<s:State name="disabled" />
</s:states>
<fx:Declarations>
<s:BlurFilter id="aBlurFilter" blurX="0" blurY="0" blurX.over="10" blurY.over="10" quality="{BitmapFilterQuality.HIGH}" />
</fx:Declarations>
<s:transitions>
<s:Transition fromState="*" toState="over">
<s:Animate id="BlurFilterTo"
target="{aBlurFilter}"
repeatCount="1"
duration="500"
repeatBehavior="reverse"
>
<s:SimpleMotionPath property="blurX" valueFrom="0" valueTo="10"/>
<s:SimpleMotionPath property="blurY" valueFrom="0" valueTo="10"/>
</s:Animate>
</s:Transition>
<s:Transition fromState="over" toState="*">
<s:Animate id="BlurFilterFrom"
target="{aBlurFilter}"
repeatCount="1"
duration="500"
repeatBehavior="reverse"
>
<s:SimpleMotionPath property="blurX" valueFrom="10" valueTo="0"/>
<s:SimpleMotionPath property="blurY" valueFrom="10" valueTo="0"/>
</s:Animate>
</s:Transition>
</s:transitions>
<s:BitmapImage id="iconDisplay" filters="{[aBlurFilter]}" />
I have created my first animation effect in flex 4. Its a very simple animation within my custom component which moves a label component left to right to left 3-5 times and then fades out gradually.
Every thing works fine but the problem is that when I run the animation first time, it plays jerky animation and perfect smoother after wards. I dont know why.
Can some one tell whats wrong with this?
This is the full source code of my custom component. After adding it to the stage, calling the showProgressEffect() will play the animation.
Notice that I have made the label "cacheAsBitmap" to avoid flickers while moving the label and call to stop() before play() methods of each of the animations/effects.
<?xml version="1.0" encoding="utf-8"?>
<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" width="274" height="72"
click="onClick()" xmlns:components="ui.hud.components.*" cacheAsBitmap="true">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
<s:Sequence id="tween" repeatCount="5" effectEnd="onEffectEnd()" >
<s:Move xBy="20" duration="500" />
<s:Move xBy="-20" duration="500" xFrom="50"/>
</s:Sequence>
<s:Fade id="fadeEffect" alphaTo="0" duration="2000" />
</fx:Declarations>
<fx:Script>
<![CDATA[
[Bindable]
public var questId:int;
[Bindable]
public var questTitle:String;
[Bindable]
public var iconUrl:String;
private function onClick():void{
Globals.questCtr.showQuest(questId);
}
private function onEffectEnd():void{
fadeEffect.stop();
fadeEffect.play([lblStatus]);
}
public function showProgressEffect():void{
tween.stop();
lblStatus.alpha = 1;
tween.play([lblStatus]);
}
]]>
</fx:Script>
<mx:Image source="{iconUrl}" width="75" height="75"/>
<s:Group x="77" y="24" width="197">
<s:Label id="lblStatus" text="Task Complete" fontWeight="bold" fontSize="25" alpha="0" cacheAsBitmap="true" hideEffect="" mouseEnabled="false"/>
</s:Group>
</s:Group>
This happens because before animation start your label is in different position, than after it. I don't know what exactly you trying to achieve, but there are two choices:
You can change xFrom="50" to xFrom="20"in second move effect;
You can change lblStatus x coordinate to 30;
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.
I am trying to do a simple animation. I want to fade in and resize a List inside creationcomplete. My problem is that I can alway see the element flash in before the element animation begin. On the other word, the user will see the element appear for 1 second->then fade in and resize animation. I was hoping anyone here could help me about it. thanks...
my code.
AS:
protected function compList_creationCompleteHandler(event:FlexEvent):void
{
compinfoResult.token = getCompList.compinfo();
compinfoResult.addEventListener(ResultEvent.RESULT, completeLoading);
function completeLoading(event:ResultEvent):void{
fadeList.play(); //the animation will fire when the List get the result from the server...
scaleList.play();
}
}
mxml
<s:Scale id="scaleList" scaleXFrom="0" scaleXTo="1" scaleYFrom="0"
scaleYTo="1" duration="500" target="{compList}" />
<s:Fade id="fadeList" alphaFrom="0" alphaTo="1" target="{compList}" />
<s:List id="compList"
width="280"
height="560"
x="0"
y="0"
alpha="0"
creationComplete="compList_creationCompleteHandler(event)"
itemRenderer="itemRenderer.compListItemRenderer"
change="compList_changeHandler(event)"/>
First off, I would combine these into a single transition, either in parallel or in sequence at your preference:
<s:Sequence id="effectSequence">
<s:Scale id="scaleList" scaleXFrom="0" scaleXTo="1" scaleYFrom="0"
scaleYTo="1" duration="500" target="{compList}" />
<s:Fade id="fadeList" alphaFrom="0" alphaTo="1" target="{compList}" />
</s:Sequence>
Then, I would not try to trigger this manually with an event. Use an effect instead, in this case I'd recommend the creationCompleteEffect.
<s:List id="compList"
width="280"
height="560"
x="0"
y="0"
alpha="0"
creationComplete="compList_creationCompleteHandler(event)"
itemRenderer="itemRenderer.compListItemRenderer"
change="compList_changeHandler(event)"
creationCompleteEffect="{effectSequence}"`/>
I have a panel with a button in it. Clicking on the button will direct the panel to state "State2" adding another two buttons into the panel. During the state change, I want the panel to resize first and then show the newly added two buttons, so I applied transitions onto the state change.
My question is:
If I put the two buttons within a HBox directly under the addChild tag, it works fine. However, if I create a new component with the same code (HBox with two buttons in it) and then add the new component to the panel (Comp in the code commented), it won't show the resize effect.
Could someone tell me how to fix this? Thanks in advance.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:local="*">
<mx:Script>
<![CDATA[
protected function button1_clickHandler(event:MouseEvent):void
{
currentState="State2";
}
]]>
</mx:Script>
<mx:transitions>
<mx:Transition>
<mx:Sequence targets="{[comp,panel1]}">
<mx:Resize target="{panel1}" />
<mx:AddChildAction />
</mx:Sequence>
</mx:Transition>
</mx:transitions>
<mx:states>
<mx:State name="State2">
<mx:AddChild relativeTo="{panel1}" position="lastChild">
<mx:HBox id="comp">
<mx:Button label="B" />
<mx:Button label="C" />
</mx:HBox>
<!--<local:Comp id="comp" />-->
</mx:AddChild>
</mx:State>
</mx:states>
<mx:Panel layout="horizontal" borderThickness="1" borderStyle="solid" id="panel1" title="AB">
<mx:Button label="A" click="button1_clickHandler(event)"/>
</mx:Panel>
</mx:Application>
I guess <mx:AddChild> tag can handle only one component at a time.
You will get your sweet resize effect if you separate your custom component to another <mx:AddChild> tag, similar to the code below:
<mx:AddChild relativeTo="{panel1}" position="lastChild">
<mx:HBox id="comp">
<mx:Button label="B" />
<mx:Button label="C" />
<!-- Don't put your custom component here. -->
</mx:HBox>
</mx:AddChild>
<!-- Use separated AddChild. Still add to same relativeTo object -->
<mx:AddChild relativeTo="{panel1}" position="lastChild">
<local:Comp id="comp2" />
</mx:AddChild>
I hope you got what you want.