Chapter 13. Using Effects and Transitions

Flex applications always consist of one or more user interface and/or container components. At a minimum, a Flex application has an application container, but usually it has many additional components. Although the default behavior for components is fairly static, you can liven up an application with the use of effects. An effect is an action that takes place, such as moving, fading, or zooming into or out of a component. An effect can even be a nonvisual behavior, such as playing a sound. Using effects, you can create applications that are more visually (and audibly) interesting. Perhaps more importantly, you can use effects to direct focus and help users better understand how to use applications.

Another way in which you can use effects is to create transitions between states. In Chapter 12, you learned about creating state views. However, so far you’ve learned how to create only sudden state changes. Using effects as transitions, you can create more interesting and seamless changes between states. For example, rather than an added component suddenly appearing, it can fade in. Not only does this generally create a more visually engaging user experience, but also effects can be used to show emphasis and to highlight change.

In this chapter, we’ll look at how to work with effects and transitions. We’ll discuss how to trigger effects, how to programmatically control effects, and even how to create custom effects. We’ll also discuss how to use an effect as a transition between states, as well as how to create custom transition types.

Using Effects

Effects are actions that you can apply to components. Common examples of effects are fades, moves, and zooms. The Flex framework includes many standard effects, as you’ll see later in Table 13-1. However, you are not limited to using those effects exclusively. You can also create composite effects both in sequence (e.g., fade, then move) and in parallel (e.g., fade and move). You can also write custom effects using ActionScript. These custom effects can then be used in exactly the same ways as standard effects.

Working with Effects

To use an effect you must first create an instance of the effect. There are two basic ways to create an effect instance: using MXML or using ActionScript. We’ll look at each technique.

MXML is arguably the most common way to create an effect instance. You need merely to add a tag of the appropriate type and give it an ID. You should place the tag as a child of the root document element. For example, you can place the tag as a child of an Application tag. The tag should never be nested within other tags (i.e., within other child components). The following example creates a new move effect instance:

<mx:Move id="moveEffect" />

Table 13-1 lists all the standard effects.

Table 13-1. Standard effects

Effect

Description

Blur

Animate a blur.

Move

Animate the motion of a component in the x and/or y direction.

Fade

Animate the alpha value of a component.

Dissolve

Animate the alpha value of a rectangular overlay.

Glow

Apply a glow to a component, and animate the appearance/disappearance of the glow.

Resize

Animate the width and height of a component.

Rotate

Rotate a component.

Zoom

Animate the x and y scales of a component.

WipeLeft, WipeRight, WipeUp, WipeDown

Apply a mask that moves to reveal or hide a component.

Iris

Apply a mask that scales to hide or reveal a component.

AnimateProperty

Animate any numeric property of a component.

Each effect in Table 13-1 has a different set of properties that you can set to customize the effect. For example, by default a move effect moves both to and from the component’s current location. The result is that the effect doesn’t seem to do anything. However, you can specify the xFrom, xTo, yFrom, and/or yTo property to affect how the component will move. The following example creates an effect that moves the component along the x-axis from −100 to the current x coordinate value:

<mx:Move id="moveEffect" xFrom="−100" />

You can also construct effects using the appropriate constructor as part of a new statement. For example, the following code creates a new Move instance:

private var moveEffect:Move = new Move();

Regardless of how you construct the effect instance, you can always set the properties using ActionScript:

moveEffect.xFrom = −100;

If you’ve created an effect using MXML, you’ll typically set the properties using MXML. However, setting the properties using ActionScript allows you to change the values at runtime. For example, you could create a blur effect using MXML, but based on different things the user does during runtime you could use ActionScript to change the properties.

Playing Effects

There are two ways in which you can play effects: using the play() method or using a trigger. We’ll look at the play() method first because it is the most straightforward way to use an effect. Then we’ll look at using triggers.

Manually playing effects

You can use the play() method of an effect to manually play the effect. For an effect to play, it must have a target to which it applies the settings. For example, if you have created a move effect instance that is supposed to move a component from −100 to its current location, you must tell it what component to use as the target. You can accomplish that using the target attribute or property. The following sets the target attribute of an effect using MXML:

<mx:Move id="moveEffect" target='{textInput1}" xFrom="−100" />

Once you’ve created an effect and assigned it a target, you can play it by calling the play() method using ActionScript:

moveEffect.play();

Example 13-1 shows an example of an effect applied in this manner. In this example, there are four text input controls and four move effects. Each move effect uses one of the text inputs as its target. Each text input is wired up such that when its creationComplete event occurs, the system tells the corresponding move effect to play.

Example 13-1. Creating and playing effects

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
    <mx:Script>
        <![CDATA[

            private function applyEffect1(event:Event):void {
                moveEffect1.play();
            }

            private function applyEffect2(event:Event):void {
                moveEffect2.play();
            }

            private function applyEffect3(event:Event):void {
                moveEffect3.play();
            }

            private function applyEffect4(event:Event):void {
                moveEffect4.play();
            }

        ]]>
    </mx:Script>

    <mx:VBox>
        <mx:TextInput id="textInput1" creationComplete="applyEffect1(event)" />
        <mx:TextInput id="textInput2" creationComplete="applyEffect2(event)" />
        <mx:TextInput id="textInput3" creationComplete="applyEffect3(event)" />
        <mx:TextInput id="textInput4" creationComplete="applyEffect4(event)" />
    </mx:VBox>

    <mx:Move id="moveEffect1" target="{textInput1}" xFrom="−100" />
    <mx:Move id="moveEffect2" target="{textInput2}" xFrom="−100" />
    <mx:Move id="moveEffect3" target="{textInput3}" xFrom="−100" />
    <mx:Move id="moveEffect4" target="{textInput4}" xFrom="−100" />

</mx:Application>

The result of the preceding code is that the four text inputs appear to slide into place from the left once they are created. As nice as that may be, it doesn’t yet demonstrate the full flexibility of working with effects. The preceding example is really quite clumsy because it has a lot of redundancy. It works, but we can improve upon it vastly using just a bit of ActionScript.

You’ve seen how to set the target of an effect using MXML. You can achieve the same result using ActionScript by assigning an object to the target property of the effect. The following example illustrates how you could assign a button as the target for a move effect:

moveEffect.target = button;

By assigning the target of an effect using ActionScript, it is possible to use one effect for more than one target. This is very useful in situations such as the one from Example 13-1 in which you have one type of effect with the same settings that you’d like to apply to more than one component. Example 13-2 shows how we can greatly simplify the code in Example 13-1 by using ActionScript to set the target.

Example 13-2. Setting the target using ActionScript

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
    <mx:Script>
        <![CDATA[

            private function applyEffect(event:Event):void {
              moveEffect.target = event.target;
              moveEffect.play();
            }

        ]]>
    </mx:Script>

    <mx:VBox>
        <mx:TextInput id="textInput1" creationComplete="applyEffect(event)" />
        <mx:TextInput id="textInput2" creationComplete="applyEffect(event)" />
        <mx:TextInput id="textInput3" creationComplete="applyEffect(event)" />
        <mx:TextInput id="textInput4" creationComplete="applyEffect(event)" />
    </mx:VBox>

    <mx:Move id="moveEffect" xFrom="−100" />

</mx:Application>

In Example 13-2, you can see that we’ve removed the redundancy by simplifying to just one effect (moveEffect) and one method (applyEffect()). Instead of setting the target of the effect using MXML, we’re setting the target at runtime using ActionScript. The result of this code is the same as that of the previous code, except this code is more elegant.

You can also specify more than one target at one time for an effect, using the targets attribute or property. With targets, you can specify an array of references to objects to which the effect should be applied. In Example 13-3, the result is visually identical to the preceding two examples, but this time the effect is played just once rather than four times.

Example 13-3. Applying an effect using targets

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
    <mx:Script>
        <![CDATA[

            private function applyEffect(event:Event):void {
                moveEffect.play();
            }

        ]]>
    </mx:Script>

    <mx:VBox creationComplete="applyEffect(event);">
        <mx:TextInput id="textInput1" />
        <mx:TextInput id="textInput2" />
        <mx:TextInput id="textInput3" />
        <mx:TextInput id="textInput4" />
    </mx:VBox>

    <mx:Move id="moveEffect"
        targets="{[textInput1, textInput2, textInput3, textInput4]}"
        xFrom="−100" />

</mx:Application>

In this example, we set the targets using MXML. You could just as easily use ActionScript to set the targets. Although there would be no real advantage to doing that in this example, in a situation in which you’d like to apply an effect to several groups of components at different times such an approach would be advantageous.

It’s also worth noting that you can apply an effect to a container. In the case of the move effect applied in the preceding examples, it would be much simpler to apply the effect to the VBox instance, as shown in Example 13-4.

Example 13-4. Applying an effect to a container

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
    <mx:Script>
        <![CDATA[

            private function applyEffect(event:Event):void {
                moveEffect.play();
            }

        ]]>
    </mx:Script>

    <mx:VBox id="vbox" creationComplete="applyEffect(event)">
        <mx:TextInput id="textInput1" />
        <mx:TextInput id="textInput2" />
        <mx:TextInput id="textInput3" />
        <mx:TextInput id="textInput4" />
    </mx:VBox>

    <mx:Move id="moveEffect" target="{vbox}" xFrom="−100" />

</mx:Application>

However, note that this works only when the result of the effect is the same when applied to the container as when applied to the child components. The preceding examples have the same visual result because the effect (move) works identically if applied to the container or the child components. This is not true for all effects; for example, a rotate effect will have a different result if applied to a container than it would if applied to the child components. The code in Example 13-5 applies a rotate effect to the individual child components.

Example 13-5. Applying a rotate effect to individual components

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
    <mx:Script>
        <![CDATA[

            private function applyEffect(event:Event):void {
                rotateEffect.target = event.currentTarget;
                rotateEffect.originX = event.currentTarget.width / 2;
                rotateEffect.originY = event.currentTarget.height / 2;
                rotateEffect.play();
            }

        ]]>
    </mx:Script>

    <!-- Set clipContent to false so that the components aren't masked
         while rotating -->
    <mx:VBox id="vbox" x="400" y="400" clipContent="false">
        <mx:TextInput id="textInput1" creationComplete="applyEffect(event)" />
        <mx:TextInput id="textInput2" creationComplete="applyEffect(event)" />
        <mx:TextInput id="textInput3" creationComplete="applyEffect(event)" />
        <mx:TextInput id="textInput4" creationComplete="applyEffect(event)" />
    </mx:VBox>

    <mx:Rotate id="rotateEffect" />

</mx:Application>

When applied this way, the individual text inputs rotate independently, each around their own center point. In Example 13-6, we’ll use the same effect, but we’ll apply it to the VBox instance instead.

Example 13-6. Applying a rotate effect to a container

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
    <mx:Script>
        <![CDATA[

            private function applyEffect(event:Event):void {
                rotateEffect.originX = event.currentTarget.width / 2;
                rotateEffect.originY = event.currentTarget.height / 2;
                rotateEffect.play();
            }

        ]]>
    </mx:Script>

    <mx:VBox id="vbox" x="400" y="400"
clipContent="false" creationComplete="applyEffect(event)">
        <mx:TextInput id="textInput1" />
        <mx:TextInput id="textInput2" />
        <mx:TextInput id="textInput3" />
        <mx:TextInput id="textInput4" />
    </mx:VBox>

    <mx:Rotate id="rotateEffect" target="{vbox}" />

</mx:Application>

This change causes the entire container to rotate, rather than each child component rotating independently.

Using triggers

Triggers occur within a Flex application to start an effect. Using triggers allows you to create and apply effects entirely with MXML. This is not necessarily better or worse than using the play() method. It is just a different way of applying effects. The biggest advantage of triggers is that they allow you to apply effects with less code and in a simpler manner than if you were applying the effects using ActionScript. Triggers give you less control, but if you don’t need too much control over an effect in a particular scenario, using a trigger is usually easier than using ActionScript.

Note

In Flex terminology, a trigger combined with an effect is called a behavior.

Standard triggers are available to all components. Table 13-2 lists these common triggers.

Table 13-2. Standard triggers

Trigger

Description

addedEffect

The component has been added to the display list.

removedEffect

The component has been removed from the display list.

creationCompleteEffect

The component has been created and initialized.

focusInEffect

The component has received focus.

focusOutEffect

The focus has moved from the component.

hideEffect

The component has been hidden (made not visible).

showEffect

The component has been shown (made visible).

rollOverEffect

The user has moved the mouse over the component.

rollOutEffect

The user has moved the mouse out of the component.

mouseDownEffect

The user has pressed the mouse button over the component.

mouseUpEffect

The user has released the mouse button over the component.

moveEffect

The x and/or y property of the component has changed.

resizeEffect

The width and/or height of the component has changed.

You can assign an effect instance to the trigger for a component, and the effect will be applied automatically when that trigger occurs. When you use triggers, you do not have to set a target for the effect. Instead, the target is automatically set when the effect is triggered. Example 13-7 uses triggers to apply a move effect to each of four text input controls as they are created.

Example 13-7. Using triggers to play effects

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">

    <mx:VBox>
        <mx:TextInput id="textInput1" creationCompleteEffect="{moveEffect}" />
        <mx:TextInput id="textInput2" creationCompleteEffect="{moveEffect}" />
        <mx:TextInput id="textInput3" creationCompleteEffect="{moveEffect}" />
        <mx:TextInput id="textInput4" creationCompleteEffect="{moveEffect}" />
    </mx:VBox>

    <mx:Move id="moveEffect" xFrom="−100" />

</mx:Application>

Of course, you can apply effects to containers using triggers as well. Example 13-8 applies the move effect to the container rather than the child components.

Example 13-8. Using triggers to play an effect on a container

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">

    <mx:VBox creationCompleteEffect="{moveEffect}">
        <mx:TextInput id="textInput1" />
        <mx:TextInput id="textInput2" />
        <mx:TextInput id="textInput3" />
        <mx:TextInput id="textInput4" />
    </mx:VBox>

    <mx:Move id="moveEffect" xFrom="−100" />

</mx:Application>

Oftentimes, triggers are the simplest way to apply an effect. As you can see, you typically need fewer lines of code to apply an effect using a trigger than you would need if you were using ActionScript. However, triggers typically work best for simple uses of effects. When you need to customize how the effect is applied, it can get more difficult to use triggers, and in those cases, it is typically better to use ActionScript.

Effect Events

All effects dispatch events that notify listeners when the effects start and when they end. Those events are called effectStart and effectEnd. The effect events are of type mx.events.EffectEvent. Example 13-9 illustrates how to use the effectEnd event to set the alpha of a container after it has moved from the left.

Example 13-9. Listening for an effectEnd event

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">

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

             private function effectEndHandler(event:EffectEvent):void {
                 // The initial alpha is .5. Once the effect is complete set the
alpha to 1.
                 vbox.alpha = 1;
             }

        ]]>
    </mx:Script>

    <mx:VBox id="vbox" alpha=".5" creationCompleteEffect="{moveEffect}">
        <mx:TextInput id="textInput1" />
        <mx:TextInput id="textInput2" />
        <mx:TextInput id="textInput3" />
        <mx:TextInput id="textInput4" />
    </mx:VBox>

    <mx:Move id="moveEffect" xFrom="−100" effectEnd="effectEndHandler(event)" />

</mx:Application>

The EffectEvent type inherits the standard event properties such as target and currentTarget. However, effects use factories to create the effect instances, and the target property of an EffectEvent object references the factory used to create the effect, not the effect instance. A factory is a programming construct that is responsible for creating objects. In this case, a Move object (or any other effect type) is a factory that creates the actual instances of the effect that get applied to components. If you need to retrieve a reference to the actual effect instance (rather than the factory), you can use the effectInstance property. Example 13-10 illustrates this by reversing a move effect once it has played.

Example 13-10. Reversing an effect

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">

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

            private function effectEndHandler(event:EffectEvent):void {
                event.effectInstance.reverse()
                event.effectInstance.play();
            }

        ]]>
    </mx:Script>

    <mx:VBox creationCompleteEffect="{moveEffect}">
        <mx:TextInput id="textInput1" />
        <mx:TextInput id="textInput2" />
        <mx:TextInput id="textInput3" />
        <mx:TextInput id="textInput4" />
    </mx:VBox>

    <mx:Move id="moveEffect" xFrom="−100" effectEnd="effectEndHandler(event)" />

</mx:Application>

The preceding examples illustrate how to add a handler for an event using an attribute. Of course, you can also add a handler using ActionScript. With ActionScript you use addEventListener as you would normally when registering any listener for any event. In that case, you can use the EffectEvent.EFFECT_START and EffectEvent.EFFECT_END constants, as shown here:

moveEffect.addEventListener(EffectEvent.EFFECT_START, effectStartHandler);
moveEffect.addEventListener(EffectEvent.EFFECT_END, effectEndHandler);

All effects dispatch effectStart and effectEnd events. Most, though not all, also dispatch tweenStart, tweenUpdate, and tweenEnd events. The tween events are inherited by all subclasses of TweenEffect and MaskEffect, which include all the effects listed in Table 13-1. The only effects that don’t dispatch tween events are composite effects (which are discussed in the next section).

Note

Tween is a word carried over from Flash. Tween is short for in between, which refers to an animation technique in which starting and ending values are given, and the intermediate values are automatically calculated. The result is that an animation (such as a translation, scale, or rotation) can be achieved quite simply by providing just the starting and ending values along with duration.

Tween events are of type mx.events.TweenEvent. The tweenStart event occurs as a tween begins, which is immediately after the effectStart event in most cases. The tweenUpdate event occurs for each change to the tweened property or properties. That means that there might be many tweenUpdate events. Then, once a tween effect has completed, it dispatches a tweenEnd event. The tweenEnd event always follows the last tweenUpdate event and precedes the effectEnd event.

The TweenEvent class defines a value property in addition to the inherited event properties. The value property contains the current value of the property or properties being changed over time. For example, for a rotate effect, the TweenEvent object’s value property is a number corresponding to the current rotation property of the component being rotated. Yet if the effect affects more than one property, the value property of the TweenEvent object is an array of the values of the affected properties. For example, a move effect animates the x and y properties of a component. The TweenEvent dispatched by a move effect has a value property that is an array with two elements corresponding to the x and y values.

Composite Effects

Not only can you create simple effects using the standard effect types, but you also can create composite effects by combining them. There are two ways you can combine effects: in sequence and in parallel.

The Sequence component allows you to group together effects that you want to occur one after the other. For example, you can use a Sequence component to first apply a fade effect and then apply a move effect. From MXML, you can simply nest the effects you want to sequence within a Sequence tag, as follows:

<mx:Sequence id="sequenceEffect">
  <mx:Fade />
  <mx:Move xTo="100" />
</mx:Sequence>

Note that in the preceding example, the Sequence instance has the id attribute, indicating that you will only need to refer to the Sequence instance rather than the nested, sequenced effects:

<mx:TextInput creationCompleteEffect="{sequenceEffect}" />

You can add a pause between sequenced effects using a pause effect. You can affect the length of the pause by specifying a value (in milliseconds) for the duration property. The following example fades a target, pauses for 1,000 milliseconds, and then moves the target:

<mx:Sequence id="sequenceEffect">
  <mx:Fade />
  <mx:Pause duration="1000" />
  <mx:Move xTo="100" />
</mx:Sequence>

The Parallel component allows you to group together effects that you want to play at the same time. For example, if you want to fade and move a component at the same time, you can use the following parallel effect:

<mx:Parallel id="parallelEffect">
  <mx:Fade />
  <mx:Move xFrom="−100" />
</mx:Parallel>

You can also nest composite effects within other composite effects. For example, the following will fade and move a target at the same time, pause for 1,000 milliseconds, and then rotate 360 degrees.

<mx:Sequence id="sequenceEffect">
  <mx:Parallel>
    <mx:Fade />
    <mx:Move xFrom="−100" />
  </mx:Parallel>
  <mx:Pause duration="1000" />
  <mx:Rotate />
</mx:Sequence>

You can also create composite effects using ActionScript. All the same rules apply to creating composite effects via ActionScript as when creating standard effects using ActionScript. The only difference is that you need a way to programmatically group effects within the composite effect. To accomplish that, use the addChild() method for the Parallel or Sequence object:

var sequenceEffect:Sequence = new Sequence();
sequenceEffect.addChild(rotateEffect);

Note

Note that although effects and display objects both have addChild() methods, you cannot add an effect to the display list, nor can you add a display object to an effect.

Pausing, Resuming, and Reversing Effects

By default, an effect plays straight through. However, you can pause, resume, and even reverse an effect. All effects have pause() and resume() methods that pause and resume the playback of an effect, respectively.

You can reverse the playback of an effect using the reverse() method as you saw in Example 13-10. If you call the reverse() method while an effect is currently playing, it will reverse from that point and play back to the start. If the effect is not playing, calling the reverse() method will not play the effect, but it will configure the effect so that the next time it is triggered or played, it will play in reverse.

Delaying and Repeating Effects

When you want to delay an effect, you have several options depending on what you are trying to accomplish. If you want to wait to start an effect until a user or system event occurs, you should associate the effect with the correct trigger or you should call the effect’s play() method in response to an event. If you want to add a timed delay before an effect starts after it’s been triggered or played, you can specify a value for the startDelay property of the effect. The startDelay property allows you to specify how many milliseconds the effect will pause before playback starts. The default value is 0, which means there is no delay. The following example creates a fade effect that adds a 1,000-millisecond delay:

<mx:Fade id="fadeEffect" startDelay="1000" />

The repeatCount property allows you to repeat the effect. The default value is 1, which means the effect plays exactly once. If you specify a value greater than 1, the effect will repeat the specified number of times. For example, the following plays the fade effect twice:

<mx:Fade id="fadeEffect" repeatCount="2" />

If you specify a value of 0, the effect repeats until you explicitly call the end() method.

You can add a delay between repeats using the repeatDelay property. The default value is 0. The value is interpreted as milliseconds.

Customizing Animation Easing

For all tween effects (blur, move, fade, glow, etc.), you can control the easing that gets applied to the effect. Easing refers to the rate at which the effect is applied over time. The default easing type is linear, meaning the effect is applied at a fixed rate from start to end. However, you may want to apply effects in a nonlinear fashion. You can apply custom easing to effects using the easingFunction property.

The easingFunction property allows you to assign a reference to a function that accepts four numeric parameters (playback time, initial value, total change in value, and duration of effect) and returns the new value to use. The effect then calls that function automatically every time it needs to update the value of a property for the target component. Although you can certainly create custom easing functions, you may find it more convenient to try one of the many easing functions that are included in the Flex framework’s mx.effects.easing package.

The mx.effects.easing package includes an assortment of classes such as Cubic, Elastic, Exponential, Quadratic, and so on. Each class has static methods called easeIn, easeOut, and easeInOut. You can reference these functions for use with effects. Here’s an example that applies an elastic easeOut to a fade effect:

<mx:Fade id="fadeEffect" easingFunction="{mx.effects.easing.Elastic.easeOut}" />

Using Effects and Fonts

You can use effects with any UI component. However, if the component contains text (e.g., labels, text inputs, etc.), the fade and rotate effects will not work as intended unless you embed the font. By default, all text in UI controls uses system fonts rather than embedded fonts. Flash Player does not properly render text for system fonts if the font in the alpha property is set to anything other than 1 or if the rotation property is not 0. Because the fade effect changes the alpha property and the rotate effect changes the rotation property, these effects will not work properly unless you embed the font. In the case of a fade effect, the text portion of the control will always be opaque. In the case of a rotate effect, the text will not be visible, except when the rotation is set to 0.

See Chapter 8 for more information about embedding fonts.

Using Effects with Lists

List-based components have built-in support for effects when the data provider changes. For example, when removing an item from a list, you may want to fade that item out from the list, or when adding an item, you may want to fade that item in. First, consider the following example, which uses a list component with the default settings such that no effects are applied:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"
creationComplete="creationCompleteHandler();">
    <mx:Script>
        <![CDATA[
            import mx.collections.ArrayCollection;
            import mx.effects.DefaultListEffect;

            [Bindable]
            private var _data:ArrayCollection;

            private function creationCompleteHandler():void {
                _data = new ArrayCollection([1, 2, 3, 4]);
            }

            private function removeSelected():void {
                var indices:Array = list.selectedIndices;
                var count:int = indices.length;
                for(var i:Number = 0; i < count; i++) {
                    _data.removeItemAt(indices[i]);
                }
            }

            private function addToList():void {
                _data.addItemAt(_data.length,
Math.floor(Math.random() * _data.length));
            }

        ]]>
    </mx:Script>
    <mx:List id="list" dataProvider="{_data}" width="100%"
        allowMultipleSelection="true" />
    <mx:Button label="Remove" click="removeSelected();" />
    <mx:Button label="Add" click="addToList();" />
</mx:Application>

The list in this example allows for multiple selections. When the user clicks on the button, the code removes all the selected elements from the list. If you were to run this code, select one or more elements from the list, and click the Remove button, you’d see that the removal of the items is instant and sudden. Likewise, if you were to click the Add button, you’d see that the addition of items is also sudden and instant. To make the whole thing a little clearer and easier to see we can add a custom item renderer to the picture. The custom item renderer we’ll use is 100 pixels high and has a random color background, making it easy to see and differentiate each item in the list. The code for the item renderer we’ll use is as follows. We’ll call this ExampleItemRenderer.mxml.

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="200" height="100"
creationComplete="creationCompleteHandler();">
    <mx:Script>
        <![CDATA[

            private function creationCompleteHandler():void {
                var randomColor:Number = Math.random() * 0xFFFFFF;
                setStyle("backgroundColor", randomColor);
            }

        ]]>
    </mx:Script>
    <mx:Label text="{data}" />
</mx:Canvas>

We can use the item renderer in the list by adding an itemRenderer attribute to the tag as follows.

<mx:List id="list" dataProvider="{_data}" width="100%" allowMultipleSelection="true"
itemRenderer="ExampleItemRenderer" />

Although not strictly necessary in this example, the custom item renderer makes the contrast between the default behavior (with no effects) and the use of effects much greater.

It’s very easy to add an effect to a list that will affect the addition and removal of items. All you need to do is assign a reference to the effect to the itemsChangeEffect attribute. Flex has a built-in effect that is configured especially for this purpose, and it is called DefaultListEffect. The following code shows how to apply this default list effect:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"
creationComplete="creationCompleteHandler();">
    <mx:Script>
        <![CDATA[
            import mx.collections.ArrayCollection;
            import mx.effects.DefaultListEffect;

            [Bindable]
            private var _data:ArrayCollection;

            private function creationCompleteHandler():void {
                _data = new ArrayCollection([1, 2, 3, 4]);
            }

            private function removeSelected():void {
                var indices:Array = list.selectedIndices;
                var count:int = indices.length;
                for(var i:Number = 0; i < count; i++) {
                    _data.removeItemAt(indices[i]);
                }
            }

            private function addToList():void {
                _data.addItemAt(_data.length,
Math.floor(Math.random() * _data.length));
            }

        ]]>
    </mx:Script>
    <mx:List id="list" dataProvider="{_data}" width="100%"
        allowMultipleSelection="true"
        itemRenderer="ExampleItemRenderer"
        itemsChangeEffect="{defaultEffect}" />
    <mx:Button label="Remove" click="removeSelected();" />
    <mx:Button label="Add" click="addToList();" />
    <mx:DefaultListEffect id="defaultEffect" />
</mx:Application>

The default list effect will cause the following behavior:

  • When an item is added the space for the new item expands and then the item fades in.

  • When an item is removed the item fades and then the space where the item was collapses.

If you were to run the preceding code, you’d likely notice that the spaces for the items don’t seem to open or collapse very smoothly in the list when adding or removing items. That’s because for a list to properly handle resizing of items you must set the list’s variableRowHeight property to true. If we change the list tag as follows, we’ll see a big difference in how the effect works:

<mx:List id="list" dataProvider="{_data}"
    width="100%" allowMultipleSelection="true"
    itemRenderer="ExampleItemRenderer"
    itemsChangeEffect="{defaultEffect}"
    variableRowHeight="true" />

You can also customize some of the settings on the effect using the following properties:

fadeInDuration and fadeOutDuration

These properties allow you to control the amount of time (in milliseconds) that it takes for added items to fade in and removed items to fade out. The default value for both is 300 milliseconds.

color

This property allows you to control the color from which and to which items fade. The default value is white.

growDuration and shrinkDuration

These properties allow you to specify the amount of time (in milliseconds) that it takes for added items to grow and removed items to shrink. The default value for both is 300 milliseconds.

removedElementOffset

This property has an effect only when removing more than one element at a time. In such cases, the removedElementOffset property determines the amount of time (in milliseconds) used to stagger the removal of the elements. The default value is 100 milliseconds. That means that by default, 100 milliseconds elapse after the first element is faded out for removal before the second element begins to fade out for removal, and so forth.

The following example creates an effect in which the elements take five seconds to fade in and out, and there's a two-second delay between the start of the fadeout of each element when more than one element is removed at the same time:

<mx:DefaultListEffect id="defaultEffect" fadeInDuration="5000" fadeOutDuration="5000"
removedElementOffset="2000" />

The default list effect allows you to customize to a point, as you’ve seen. However, if you want to create a completely custom effect, you can do that as well. If you decide to create a custom effect, you need to package the effect in a sequence, and you should assign filters to the effect. You can assign filters using the filter attribute for each effect. A filter determines when an effect is applied and when it is not applied. There are two filter names used by the itemsChangeEffect for a list control: addItem and removeItem. The following is an example of a custom effect that we can apply to a list. This effect uses easing to create a bounce effect as the items open or collapse.

<mx:Sequence id="customEffect">
    <mx:Sequence filter="removeItem">
        <mx:Fade alphaFrom="1" alphaTo="0" duration="2000" />
        <mx:Resize heightTo="0" duration="2000"
easingFunction="{mx.effects.easing.Bounce.easeOut}" />
    </mx:Sequence>
    <mx:Sequence filter="addItem">
        <mx:Resize heightFrom="0" duration="2000"
easingFunction="{mx.effects.easing.Bounce.easeIn}" />
        <mx:Fade alphaFrom="0" alphaTo="1" duration="2000" />
    </mx:Sequence>
</mx:Sequence>

Tile lists also support the itemsChangeEffect attribute. Tile lists work almost identically to lists in this regard. However, there are a few minor differences:

  • You cannot use the DefaultListEffect with tile lists. Instead, you must use DefaultTileListEffect.

  • When you use an effect with a tile list, you should set the offscreenExtraRowsOrColumns to 2 to achieve the smoothest effects.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset