This article is sponsored by Adobe.
Animating Spark Skins in Flex 4
by Chet Haase
February 21, 2011

Summary
With a demo app from his book, Flex 4 Fun, Chet Haase shows how to use state transitions with the new Spark component architecture in Flex 4 to create dynamic component skins for better user experiences.
Advertisements
This article is based on
material from the book
Flex 4 Fun by Chet Haase,
available;
from Artima Press.

In a previous article, Interactive Spark Components in Flex 4, I showed how to use the new state syntax in Flex 4 to add interactivity to a button. This interactivity added critical feedback to the component, enabling the user to understand, through visual changes in the button's appearance, important changes in state that affected the button's functionality, like hovering over and clicking the button. That version of the button is pretty good—it looks modern and rich, and interacts appropriately as the user interacts with it. But sometimes, you may want enhanced interactivity, not just switching to different states, but instead animating between them.

I discussed animated transitions in a previous article on Artima, State Transitions in Flex 4. Transitions can be used to help the user understand changes in the state of the application and to help them process potentially complicated UIs. Animations can guide the user through changes in the interface, as shown in that previous article's example of the screens of a simple search application. Transitions can also be used at the component level, animating changes in a component's skin state just as they can animate changes in application state. This article will show how easy it is to add these animated transitions to a button's skin.

In the button example from the previous article on component skinning, I added state-specific values to the GradientEntry objects of the button's fill to vary the gradient colors and ratios between the up, over, and down states, resulting in this code:

    <s:fill>
        <s:LinearGradient rotation="90">
            <s:GradientEntry color="0xf0f0f0"
                color.over="0xc0c0c0" color.down="0xa0a0a0"/>
            <s:GradientEntry color="0xffffff"
                color.over="0xf0f0f0" color.down="0x808080"
                ratio=".1" ratio.down=".2"/>
            <s:GradientEntry color="0xaaaaaa"
                color.over="0x808080" color.down="0xc0c0c0"/>
        </s:LinearGradient>
    </s:fill>

For the animated version of the skin, I'll use these same objects, adding only id elements so that the code can reference the objects that will be animated. I will also add state-specific strength values to the DropShadow object, to further enhance the difference between the states (and to show how to enable multiple, different animations in the same transition). These changes result in the following code (differences from the previous version are shown in bold):

    <s:DropShadowFilter id="shadow" strength=".3"
        strength.over=".4" strength.down=".5"/>
        <s:fill>
        <s:LinearGradient rotation="90">
            <s:GradientEntry id="ge1" color="0xf0f0f0"
                color.over="0xc0c0c0" color.down="0xa0a0a0"/>
            <s:GradientEntry id="ge2" color="0xffffff"
                color.over="0xf0f0f0" color.down="0x808080"
                ratio=".1" ratio.down=".2"/>
            <s:GradientEntry id="ge3" color="0xaaaaaa"
                color.over="0x808080" color.down="0xc0c0c0"/>
        </s:LinearGradient>
    </s:fill>

There are different ways to add animation to an application, but the easiest way to animate changes in state values is to use transitions. Flex transitions predate Flex 4, although the animated effects used in transitions were enhanced in the Flex 4 release. Transitions enable developers to create powerful animations by simply declaring which state changes they want to animate, the types of animations desired, and the objects and properties affected by the animation. The rest of the details are handled by the Flex framework: the actual values animated between are derived from the state-specific data of the objects.

For instance, the following example is going to animate the color property in the GradientEntry objects in the skin. Since this property knows the values that it will have in the various states, a transition between those states need not specify values for the animation; the Flex transition mechanism will derive them from the state information and populate the animation values appropriately. (In fact, as I discuss in the book, it's better to not hard-code values in the animation, but to let the transition engine determine the properties for you. This approach avoids causing problems when the animation values may not match the values in the states).

To use transitions in a skin (or in any MXML file), you declare a transitions block, just like the states block which declares the states used by the skin. Inside the transitions block, you declare a series of Transition objects for the state changes that you want to animate. Inside of each Transition object, you then declare the animation effects that you want to run during that state transition. For example, the transitions block for the animated button example looks like this (some parts are commented-out, to be shown later):

    <s:transitions>
        <s:Transition>
            <!-- animation effects... -->
        </s:Transition>
        <s:Transition toState="down">
            <!-- animation effects... -->
        </s:Transition>
        <s:Transition fromState="down">
            <!-- animation effects... -->
        </s:Transition>
    </s:transitions>

In this transitions block, we have one default transition (with no specified fromState or toState) which will play during any state transition if no other state-specific transition plays. We also have two transitions that will play when the state enters or exits the down state (for a reason that we'll see later).

The types of animation effects possible in state transitions are infinite, bounded only by the properties that you want to animate during state changes. But in general, transitions consist of effects like Move and Fade as objects change position and visibility between states. You can see these effects in use in the transitions article mentioned above.

In this button example, however, we want to animate properties that are not handled by the Move and Fade effects; we will be animating the strength of the drop shadow, the gradient ratio, and the gradient colors. For these animations, we will need to use general-purpose Animate effect and the AnimateColor effect.

The Animate effect was created in Flex 4 to handle animating arbitrary properties on objects; you tell it the target object to animate and the properties on that object and it animates between the values specified (or the values picked up from the states, as in the example here). Other effects like Move and Fade operate on specific properties of the target object, whereas Animate can act on any property. Animate is like the AnimateProperty effect in Flex 3, although Animate can handle multiple properties simultaneously, and shares other capabilities of the new Flex 4 effects like arbitrary type interpolation. In fact, Animate is the superclass of all of the new Flex 4 effects and is the main engine behind these new effects, so any use of one of the new effects will actually be using Animate behind the scenes. But we will be using the effect directly here as we animate the ratio and strength properties.

We have two target objects to use Animate on: the DropShadow and second GradientEntry (the only one whose ratio changes between states). We therefore use two Animate effects to run animations on these two target objects:

    <s:Animate target="{shadow}">
        <s:SimpleMotionPath property="strength"/>
    </s:Animate>
    <s:Animate target="{ge2}">
        <s:SimpleMotionPath property="ratio"/>
    </s:Animate>

These effects will animate the strength property on the shadow object and the ratio property on the ge2 object. The start and end values are determined automatically based on the values of those properties in the states being animated between.

To animate the color property of the gradient, we use the AnimateColor effect. We could also use Animate to animate the color, but colors require a bit more care to animate (you cannot simply animate colors as numbers, like Animate does by default; you need to set a type interpolator on the effect to interpolate the color values correctly). AnimateColor handles the details for us, correctly interpolating RGB colors.

  <s:AnimateColor targets="{[ge1, ge2, ge3]}"/>

Note here that this one effect is animating all three gradient entries independently; we just set all three objects as targets of the effect.

The last detail of the animations is that a Transition object encapsulates a single animation effect. But in this case, we want to run all three effects at the same time. We we wrap the effects with a Parallel effect, which plays the animations simultaneously. Putting it all together, we end up with the following transitions block in the skin:

    <s:transitions>
        <s:Transition>
            <s:Parallel duration="500">
                <s:Animate target="{shadow}">
                    <s:SimpleMotionPath property="strength"/>
                </s:Animate>
                <s:Animate target="{ge2}">
                    <s:SimpleMotionPath property="ratio"/>
                </s:Animate>
                <s:AnimateColor targets="{[ge1, ge2, ge3]}"/>
            </s:Parallel>
        </s:Transition>
        <s:Transition toState="down">
            <s:Parallel duration="250">
                <s:Animate target="{shadow}">
                    <s:SimpleMotionPath property="strength"/>
                </s:Animate>
                <s:Animate target="{ge2}">
                    <s:SimpleMotionPath property="ratio"/>
                </s:Animate>
                <s:AnimateColor targets="{[ge1, ge2, ge3]}"/>
            </s:Parallel>
        </s:Transition>
        <s:Transition fromState="down">
            <s:Parallel duration="250">
                <s:Animate target="{shadow}">
                    <s:SimpleMotionPath property="strength"/>
                </s:Animate>
                <s:Animate target="{ge2}">
                    <s:SimpleMotionPath property="ratio"/>
                </s:Animate>
                <s:AnimateColor targets="{[ge1, ge2, ge3]}"/>
            </s:Parallel>
        </s:Transition>
    </s:transitions>

Note that the only difference between the three transitions is the duration assigned to the effects; we use a duration of 500 for the default transition (which will take place when the mouse moves over and out of the button area) and 250 for the other transitions. This difference is important because the action of clicking on the button should generally be much quicker than a more transitional animation like moving the mouse over the button. When the user clicks the button, you want to action to occur very quickly, and not to make them wait for an animation to occur, which can make the application appear sluggish. Pretty, but sluggish.

In fact, durations of 500 and 250 milliseconds are far too long for both of these animations. I only made them that long to make the animations obvious when playing with the demo in this article. The click animation should be very quick, like 50 ms. In fact, skipping an animation on an atomic action like clicking is the best approach in many cases. But if you do add an animation to it, make it quick. The other animation can be longer, but more like 200 ms than the current 500 ms; long enough to animate the change, but not so long that the user feels that it's sluggish.

Run the demo application below. By default, the button uses the Stateful skin. When you hover over and click on the button, notice the sudden changes in the button's visual appearance. Now select the Animated skin from the drop down list. Notice that the mouse interactions now trigger animations between those visual states.

To view this page ensure that Adobe Flash Player version 10.0.0 or greater is installed.

Either scripts and active content are not permitted to run or Adobe Flash Player version 10.0.0 or greater is not installed.

Get Adobe Flash Player

As you can see from the demo application, it is easy to add animations to your component skins, building on the states capabilities of Flex to animate changes in state. All I did to take the previous button example to an animated version was to add reference ids and a transitions block to declare the animations to use (plus a change in the DropShadow's strength property just to add more to the overall effect).

The source code for this application and its two skins can be found here. For more information on the topics covered in this article, check out the previous articles on transitions and component skinning, plus the following Flex 4 Fun chapters: States, Transitions, and Skinning Components, and several chapters on Flex 4 effects.

Resources

Chet Haase is author of Flex 4 Fun, which is available as a PrePrint™ (early access release) at:
http://www.artima.com/shop/flex_4_fun

Adobe's Flash Builder 4
http://www.adobe.com/products/flashbuilder

Flex SDK 4
http://opensource.adobe.com/wiki/display/flexsdk/Flex+SDK

Chet's article "Interactive Spark Components in Flex 4" is at:
http://www.artima.com/articles/interactive_spark_components_in_flex.html

Chet's article "State Transitions in Flex 4" is at:
http://www.artima.com/articles/state_transitions_in_flex_4.html

For more on states in Flex 4, see "Working with States in Flex 4":
http://www.artima.com/articles/flex_4_states.html

Flex.org
http://www.flex.org

Talk back!

Have an opinion? Be the first to post a comment about this article.

About the author

Chet Haase worked as a senior computer scientist on the Flex SDK team at Adobe Systems, Inc., during the Flex 4 release. He was responsible for Flex effects, and writing the next effects infrastructure and classes for Flex 4. Prior to his work at Adobe, he worked at Sun Microsystems for several years, and co-authored the book Filthy Rich Clients about creating rich user experiences with the Java client platform. His entire career has been in graphics software, from the application level to APIs and libraries to drivers for graphics chips. As long as it puts pixels on the screen, he's interested. He earned a B.A. in Mathematics from Carleton College and an M.S. in Computer and Information Sciences from the University of Oregon.

Chet posts regularly to his technical blog at http://graphics-geek.blogspot.com, where you can find articles, videos, demos, and plenty of source code. Chet is also interested in writing and performing comedy; you can see some his work in this completely unrelated field at http://chetchat.blogspot.com, and in his book When I am King..., which is available at Amazon.com.