How can I stop a skin animation?

272 Views Asked by At

I have a custom component with a skin attached to it.
There are several different skins for this component, and they are all animated differently. Therefor I've contained the animations with the skinClasses.
When the component is no longer in view, I need to be able to stop the animations so they don't run in the background.

How can I call a stop function on a skin?

My guess was to add two skin states: "animationState" and "idleState".
But the following code does not stop the animation when close() is called. The skinState does not change.

package {
    import spark.components.supportClasses.SkinnableComponent;

    [SkinState("animationState")]   
    [SkinState("idleState")]

    public class AnimatedComponent extends SkinnableComponent
    {
        public function AnimatedComponent
        {
            setStyle("skinClass", MyAnimatedComponentSkin);
        }

        public function start():void
        {
            _isAnimating = true;
            invalidateSkinState();
        }
        public function close():void
        {
            _isAnimating = false;
            invalidateSkinState();
        }

        private var _isAnimating:Boolean = false;
        override protected function getCurrentSkinState():String
        {
            return _isAnimating ? "animationState" : "idleState";
        }
    }
}
1

There are 1 best solutions below

0
On

Here's an example of the way I did it (This doesn't actually answer my question at all, but it worked for what I needed. Hopefully this helps someone else struggling with a similar problem).

I have an Application with a custom skinnable Title and a "STOP" button.
I've created a base class called MyCustomTitle which extends spark.components.supportClasses.SkinnableComponent, and used a stylesheet "main.css" to apply the skinclass to it.

Also, when the app is loaded from the browser, the web-script passes a "theme" parameter to the Application (this.parameters.theme). This allows the user to choose the theme, which will determine the skins/animations.

<?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"
               applicationComplete="application1_applicationCompleteHandler(event)">

    <fx:Style source="main.css" />

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

            /**
             * An custom component that displays an animated Label
             */
            public var myComponent:MyCustomTitle;

            protected function application1_applicationCompleteHandler(event:FlexEvent):void
            {
                var theme:String = this.parameters.theme;                   
                switch(theme) {
                    case "red":
                        myComponent = new MyScalingTitle();                     
                        break;
                    default:
                        myComponent = new MyFadingTitle();                      
                        break;
                }
                myComponent.styleName = theme;
                myComponent.text = "Hello World";
                addElementAt(myComponent, 0);
                myComponent.init();
            }

            private function stop_clickHandler(event:MouseEvent):void
            {
                myComponent.stop();
            }

        ]]>
    </fx:Script>

    <s:layout>
        <s:VerticalLayout />
    </s:layout>

    <s:Button label="STOP" click="stop_clickHandler(event)"/>
</s:Application>

Here is the CSS file that defines the skin:

/* CSS file */
@namespace s "library://ns.adobe.com/flex/spark";
@namespace mx "library://ns.adobe.com/flex/mx";
@namespace local "*";


local|MyCustomTitle
{
    skinClass: ClassReference("MyCustomTitleBlueSkin");
}

local|MyCustomTitle.red
{
    skinClass: ClassReference("MyCustomTitleRedSkin");
}

Here is the "red" 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">
    <!-- host component -->
    <fx:Metadata>
        [HostComponent("MyCustomTitle")]
    </fx:Metadata>

    <!-- SkinParts
    name=labelDisplay, type=spark.components.Label, required=true
    -->
    <s:Label id="labelDisplay" color="0xFF0000" />
</s:Skin>

And the "blue" one:

<?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:mx="library://ns.adobe.com/flex/mx">
    <!-- host component -->
    <fx:Metadata>
        [HostComponent("MyCustomTitle")]
    </fx:Metadata>

    <!-- SkinParts
    name=labelDisplay, type=spark.components.Label, required=true
    -->
    <s:Label id="labelDisplay" color="0x0000FF" />
</s:Skin>

I could have put the animations in the skin classes above. This would work perfectly fine for a non-repeating animation. But because these animations loop, I need to be able to call a stop() function on them when they are not being displayed. Since I cannot call functions in the skin, I am instead adding the animation into the hostComponent Class.

MyCustomTitle has a required labelDisplay property for the skins.
The animation is defined here, because some of the animation properties are shared between all the different themes. However, as of right now, the animation is null.
This class has an init() method to start the animation, and a stop() method.

package
{   
    import spark.components.Label;
    import spark.components.supportClasses.SkinnableComponent;
    import spark.core.IDisplayText;
    import spark.effects.Animate;
    import spark.effects.animation.RepeatBehavior;

    public class MyCustomTitle extends SkinnableComponent implements IDisplayText
    {
        //Custom component that has a label and a skin

        [SkinPart(required="true")]
        /**
         * Button is required in the skin
         */
        public var labelDisplay:Label;

        //set common parameters that the animation will share
        protected var animate:Animate;      
        override protected function createChildren():void
        {
            super.createChildren();
            labelDisplay.text = _label;
            animate = createAnimation();
            if(animate != null) {
                animate.repeatCount = 0;
                animate.repeatBehavior = RepeatBehavior.REVERSE;
                animate.duration = 500;
            }
        }

        //build the animation here
        protected function createAnimation():Animate
        {
            //override to create dynamic animation
            return null;
        }

        //play the animation
        public function init():void
        {
            if(animate != null)
                animate.play([labelDisplay]);
        }

        //stop the animation
        public function stop():void
        {
            if(animate != null)
                animate.stop();
        }

        //components implements IDisplayText
        public function set text(value:String):void
        {
            _label = value;
            if(labelDisplay)
                labelDisplay.text = value;
        }

        public function get text():String
        {
            return _label;
        }
        private var _label:String;

        public function get isTruncated():Boolean
        {
            return labelDisplay.isTruncated;
        }
    }
}

Finally, I can extend MyCustomTitle so that it can have a different animation for each theme.

Theme "red":

package
{
    import spark.effects.Animate;
    import spark.effects.Scale;

    public class MyScalingTitle extends MyCustomTitle
    {       
        override protected function createAnimation():Animate
        {
            var _scale:Scale = new Scale(labelDisplay);
            _scale.scaleXFrom = 0;
            _scale.scaleYFrom = 0;
            _scale.scaleXTo = 1;
            _scale.scaleYTo = 1;
            return _scale;
        }
    }
}

Theme "blue":

package
{
    import spark.effects.Animate;
    import spark.effects.Fade;

    public class MyFadingTitle extends MyCustomTitle
    {       
        override protected function createAnimation():Animate
        {
            var _fade:Fade = new Fade(labelDisplay);
            _fade.alphaFrom = 0;
            _fade.alphaTo = 1;
            return _fade;
        }
    }
}