Flex implements effects by using an architecture in which each effect is represented by two classes: a factory class and an instance class. Therefore, to implement a custom effect, you create two classes: the factory class and the instance class.
You create a factory class by creating a subclass of the mx.effects.Effect class, or by creating a subclass of one of the subclasses of the mx.effects.Effect class. You create an instance class by creating a subclass of the mx.effects.EffectInstance class, or a subclass of one of the subclasses of the mx.effects.EffectInstance class.
The following image shows the class hierarchy for effects:
To define a custom effect, you create two classes: the factory class and the instance class:
Factory class
The factory class creates an object of the instance class to perform the effect on the target. You create a factory class instance in your application, and configure it with the necessary properties to control the effect, such as the zoom size or effect duration. You then assign the factory class instance to an effect trigger of the target component, as the following example shows:
<!-- Define factory class. -->
<mx:WipeDown id="myWD" duration="1000"/>
<!-- Assign factory class to effect targets. -->
<mx:Button id="myButton" mouseDownEffect="{myWD}"/>
<mx:Button id="myOtherButton" mouseDownEffect="{myWD}"/>
By convention, the name of a factory class is the name of the effect, such as Zoom or Fade.
Instance class
The instance class implements the effect logic. When an effect trigger occurs, or when you call the play() method to invoke an effect, the factory class creates an object of the instance class to perform the effect on the target. When the effect ends, Flex destroys the instance object. If the effect has multiple target components, the factory class creates multiple instance objects, one per target.
By convention, the name of an instance class is the name of the effect with the suffix Instance, such as ZoomInstance or FadeInstance.
You define effects by creating a subclass from the effects class hierarchy. Typically, you create a subclass from one of the following classes:
You must override several methods and properties in your custom effect classes, and define any new properties and methods that are required to implement the effect. You can optionally override additional properties and methods based on the type of effect that you create.
The following table lists the methods and properties that you define in a factory class:
|
Factory method/property |
Description |
|---|---|
| constructor |
(Required) The class constructor. You typically call the super() method to invoke the superclass constructor to initialize the inherited items from the superclasses. Your constructor must take at least one optional argument, of type Object. This argument specifies the target component of the effect. |
| Effect.initInstance() |
(Required) Copies properties of the factory class to the instance class. Flex calls this protected method from the Effect.createInstance() method; you do not have to call it yourself. In your override, you must call the super.initInstance() method. |
| Effect.getAffectedProperties() |
(Required) Returns an Array of Strings, where each String is the name of a property of the target object that is changed by this effect. If the effect does not modify any properties, it should return an empty Array. |
| Effect.instanceClass |
(Required) Contains an object of type Class that specifies the name of the instance class for this effect class. All subclasses of the Effect class must set this property, typically in the constructor. |
| Effect.effectEndHandler() |
(Optional) Called when an effect instance finishes playing. If you override this method, ensure that you call the super() method. |
| Effect.effectStartHandler() |
(Optional) Called when the effect instance starts playing. If you override this method, ensure that you call the super() method. |
|
Additional methods and properties |
(Optional) Define any additional methods and properties that the user requires to configure the effect. |
The following table lists the methods and properties that you define in an instance class:
|
Instance method/property |
Description |
|---|---|
|
constructor |
(Required) The class constructor. You typically call the super() method to invoke the superclass constructor to initialize the inherited items from the superclasses. |
| EffectInstance.play() |
(Required) Invokes the effect. You must call super.play() from your override. |
| EffectInstance.end() |
(Optional) Interrupts an effect that is currently playing, and jumps immediately to the end of the effect. |
| EffectInstance.initEffect() |
(Optional) Called if the effect was triggered by the EffectManager. You rarely have to implement this method. For more information, see Overriding the initEffect() method. |
| TweenEffectInstance.onTweenUpdate() |
(Required) Use when you create a subclass from TweenEffectInstance. A callback method called at regular intervals to implement a tween effect. For more information, see Example: Creating a tween effect. |
| TweenEffectInstance.onTweenEnd() |
(Optional) Use when you create a subclass from TweenEffectInstance. A callback method called when the tween effect ends. You must call super.onTweenEnd() from your override. For more information, see Example: Creating a tween effect. |
|
Additional methods and properties |
(Optional) Define any additional methods and properties. These typically correspond to the public properties and methods from the factory class, and any additional properties and methods that you require to implement the effect. |
To define a simple custom effect, you create a factory class from the Effect base class, and the instance class from the mx.effects.EffectInstance class. The following example shows an effect class that uses a Sound object to play an embedded MP3 file when a user action occurs. This example is a simplified version of the SoundEffect class that ships with Flex.
package myEffects
{
// myEffects/MySound.as
import mx.effects.Effect;
import mx.effects.EffectInstance;
import mx.effects.IEffectInstance;
public class MySound extends Effect
{
// Define constructor with optional argument.
public function MySound(targetObj:Object = null) {
// Call base class constructor.
super(targetObj);
// Set instanceClass to the name of the effect instance class.
instanceClass= MySoundInstance;
}
// This effect modifies no properties, so your
// override of getAffectedProperties() method
// returns an empty array.
override public function getAffectedProperties():Array {
return [];
}
// Override initInstance() method.
override protected function initInstance(inst:IEffectInstance):void {
super.initInstance(inst);
}
}
}
The package statement in your class specifies that you should deploy it in a directory called myEffects. In this example, you place it in the subdirectory of the directory that contains your Flex application. Therefore, the namespace definition in your Flex application is xmlns:MyComp="myEffects.*". For more information on deployment, see Component Compilation.
To define your instance class, you create a subclass from the mx.effects.EffectInstance class. In the class definition, you must define a constructor and play() methods, and you can optionally define an end() method to stop the effect.
package myEffects
{
// myEffects/MySoundInstance.as
import mx.effects.EffectInstance;
import flash.media.SoundChannel;
import flash.media.Sound;
public class MySoundInstance extends EffectInstance
{
// Embed the MP3 file.
[Embed(source="sample.mp3")]
[Bindable]
private var sndCls:Class;
// Define local variables.
private var snd:Sound = new sndCls() as Sound;
private var sndChannel:SoundChannel;
// Define constructor.
public function MySoundInstance(targetObj:Object) {
super(targetObj);
}
// Override play() method.
// Notice that the MP3 file is embedded in the class.
override public function play():void {
super.play();
sndChannel=snd.play();
}
// Override end() method class to stop the MP3.
override public function end():void {
sndChannel.stop();
super.end();
}
}
}
To use your custom effect class in an MXML file, you insert a tag with the same name as the factory class in the MXML file. You reference the custom effect the same way that you reference a standard effect.
The following example shows an application that uses the MySound effect:
<?xml version="1.0"?>
<!-- effects/MainSoundEffect.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:MyComp="myEffects.*">
<MyComp:MySound id="mySoundEffect" />
<!-- Use the SoundEffect effect with a mouseOver trigger. -->
<mx:Label text="play MP3" rollOverEffect="{mySoundEffect}" />
</mx:Application>
The executing SWF file for the previous example is shown below:
To make your effects more robust, you often design them to let the user pass parameters to them. The example in this section modifies the sound effect from the previous section to take a parameter that specifies the MP3 file to play:
package myEffects
{
// MySoundParam.as
import mx.effects.Effect;
import mx.effects.EffectInstance;
import mx.effects.IEffectInstance;
public class MySoundParam extends Effect
{
// Define a variable for the MP3 URL
// and give it a default value.
public var soundMP3:String=
"http://localhost:8100/flex/assets/default.mp3";
// Define constructor with optional argument.
public function MySoundParam(targetObj:Object = null) {
// Call base class constructor.
super(targetObj);
// Set instanceClass to the name of the effect instance class.
instanceClass= MySoundParamInstance;
}
// Override getAffectedProperties() method to return an empty array.
override public function getAffectedProperties():Array {
return [];
}
// Override initInstance() method.
override protected function initInstance(inst:IEffectInstance):void {
super.initInstance(inst);
// initialize the corresponding parameter in the instance class.
MySoundParamInstance(inst).soundMP3 = soundMP3;
}
}
}
In the MySoundParam class, you define a variable named soundMP3 that enables the user of the effect to specify the URL of the MP3 file to play. You also modify your override of the initInstance() method to pass the value of the soundMP3 variable to the instance class.
Notice that the getAffectedProperties() method still returns an empty Array. That is because getAffectedProperties() returns the list of properties of the effect target that are modified by the effect, not the properties of the effect itself.
In your instance class, you define a property named soundMP3, corresponding to the property with the same name in the factory class. Then, you use it to create the URLRequest object to play the sound, as the following example shows:
package myEffects
{
// MySoundParamInstance.as
import mx.effects.EffectInstance;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.net.URLRequest;
public class MySoundParamInstance extends EffectInstance
{
// Define local variables.
private var s:Sound;
private var sndChannel:SoundChannel;
private var u:URLRequest;
// Define a variable for the MP3 URL.
public var soundMP3:String;
// Define constructor.
public function MySoundParamInstance(targetObj:Object) {
super(targetObj);
}
// Override play() method.
override public function play():void {
// You must call super.play() from within your override.
super.play();
s = new Sound();
// Use the new parameter to specify the URL.
u = new URLRequest(soundMP3);
s.load(u);
sndChannel=s.play();
}
// Override end() method to stop the MP3.
override public function end():void {
sndChannel.stop();
super.end();
}
}
}
You can now pass the URL of an MP3 to the effect, as the following example shows:
<?xml version="1.0"?>
<!-- effects/MainSoundParam.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:MyComps="myEffects.*">
<MyComps:MySoundParam id="mySoundEffect"
soundMP3="http://localhost:8100/flex/assets/sample.mp3"/>
<!-- Use the SoundEffect effect with a mouseOver trigger. -->
<mx:Label text="play MP3" rollOverEffect="mySoundEffect"/>
</mx:Application>