Animation: A change in value over time. Anyone reading this spec probably already knows this basic concept, but I wanted to call it out specifically because the whole tenet of the approach with this feature is to make our effects more generic, to have them animate 'properties' instead of calling specific functions in specifically-typed target objects.
A more complete title for this spec might be "Effects for Arbitrary Objects, including the Gumbo Components and FXG Elements" as this feature solves a more general problem than just animating the new components. But it seemed a bit wordy for a spec title.
The current Effect classes in Halo are constrained to operate on UIComponent subclasses, through dependencies on certain properties, specific functions, and general concepts of how UIComponents behave.
In Gumbo, we are introducing the new FXG elements, which are not subclasses of UIComponent, and which therefore will not be able to be targets of the current Effect classes.
Our effects are essentially changing properties on their targets, so there is really nothing inherent in effects that must constrain them to operate solely on UIComponent objects. So why constrain them at all? Instead, let's create an effects structure such that any Effect can be applied generically to any object: old components, new components, our new FXG elements, or any arbitrary object written by us or our developers.
These Effects will be used in all situations that effects are currently used: to change properties in target objects due to either specified settings ("Move from here to there") or implicit settings ("Transition from this state of the target to that state" and "Move the target based on the information in this MoveEvent").
Since the usage of these effects is broader than just new (and old) Flex components, they will also be used in broader situation, such as animating graphics objects and any other arbitrary objects that the user wants to affect.
This feature is about introducing a new effects infrastructure where effects will subclass a variant of AnimateProperty. But where AnimateProperty animates a single named property on a target, the new Animate base class animates an arbitrary number of properties. The new effects will set values in the targets by simply calling the setter (or setStyle, when the named property is a style instead) for each property.
Setting named properties in this way is what AnimateProperty does (for a single property), but not what the other previous effects do. Instead, they call known functions in the target. For instance, the Move effect calls target.move(x,y). Not only does the current approach require that the target object implement the specific function used by the effect, but it also means that effects are using a parallel system of setting these properties to the system used by other clients of that target.
The new approach will simply set properties on the target object in the usual way. For example, instead of move(x,y), Move will call target["x"] = x and target["y"] = y.
Many of the old effects will be ported over to this system, starting with the core effects considered most useful (such as Move, Resize, and Fade).
For now, we anticipate these effects being new classes; we are not proposing changing the old effects. These new effects should work on both old and new components, so developers will be encouraged to switch to the new effects in general. But in the interest of not breaking applications that still use the old effects, we are not proposing changing the behavior of those classes, but will just let them continue in their current mode while we develop parallel effects. Once we have a working system, we can come back to the question of whether to have new effects or port the behavior back to the old effect classes.
The new effects will go into the new spark.effects package.
Note that triggers do not currently work on the new effects. We should come back to this later to determine whether to retrofit triggers onto these new classes or leave Triggers behind for older components and effects.
In the following classes:
PropertyValuesHolder:
/**
* This class is used to hold the name of a property and the values that
* that property will assume over time for instances of the AnimateProperties
* effect, or subclasses of that effect.
*/
public class PropertyValuesHolder
{
/**
* The name of the property
*/
public var property:String;
/**
* The values that the named property will assume over time. In the current
* release, these properties are simply the from/to values that the property
* is moving linearly between.
*/
public function get values():Array {}
public function set values(newValues:Array):void {}
public function PropertyValuesHolder(property:String = null, values:Array = null) {}
public function toString():String {}
}
Animate and AnimateInstance:
<a href="DefaultProperty%28%26quot%3BpropertyValuesList%26quot%3B%29">DefaultProperty("propertyValuesList")</a>
/**
* Dispatched when the effect starts, which corresponds to a
* call to the <code>AnimateInstance.startHandler()</code> method.
* Flex also dispatches the first <code>animationUpdate</code> event
* for the effect at the same time.
*
* <p>The <code>Effect.effectStart</code> event is dispatched
* before the <code>animationStart</code> event.</p>
*
* @eventType mx.events.AnimationEvent.ANIMATION_START
*/
<a href="Event%28name%3D%26quot%3BanimationStart%26quot%3B%2C%20type%3D%26quot%3Bmx.events.AnimationEvent%26quot%3B%29">Event(name="animationStart", type="mx.events.AnimationEvent")</a>
/**
* Dispatched every time the effect updates the target.
* This event corresponds to a call to
* the <code>AnimateInstance.updateHandler()</code> method.
*
* @eventType mx.events.AnimationEvent.ANIMATION_UPDATE
*/
<a href="Event%28name%3D%26quot%3BanimationUpdate%26quot%3B%2C%20type%3D%26quot%3Bmx.events.AnimationEvent%26quot%3B%29">Event(name="animationUpdate", type="mx.events.AnimationEvent")</a>
/**
* Dispatched when the effect begins a new repetition, for
* any effect that is repeated more than once.
* This event corresponds to a call to
* the <code>AnimateInstance.repeatHandler()</code> method.
* Flex also dispatches an <code>animationUpdate</code> event
* for the effect at the same time.
*
* @eventType mx.events.AnimationEvent.ANIMATION_REPEAT
*/
<a href="Event%28name%3D%26quot%3BanimationRepeat%26quot%3B%2C%20type%3D%26quot%3Bmx.events.AnimationEvent%26quot%3B%29">Event(name="animationRepeat", type="mx.events.AnimationEvent")</a>
/**
* Dispatched when the effect ends.
* This event corresponds to a call to
* the <code>AnimateInstance.endHandler()</code> method.
* Flex also dispatches an <code>animationUpdate</code> event
* for the effect at the same time.
*
* <p>This event occurs just before an <code>effectEnd</code> event.
* A repeating effect dispatches this event only after the
* final repetition.</p>
*
* @eventType mx.events.AnimationEvent.ANIMATION_END
*/
<a href="Event%28name%3D%26quot%3BanimationEnd%26quot%3B%2C%20type%3D%26quot%3Bmx.events.AnimationEvent%26quot%3B%29">Event(name="animationEnd", type="mx.events.AnimationEvent")</a>
/**
* This effect animates an arbitrary set of properties between values, as specified
* in the <code>propertyValuesList</code> array. Example usage is as follows:
*
* @example Using the Animate effect to move a button from (100, 100)
* to (200, 150):
* <listing version="3.0">
* var button:Button = new Button();
* var anim:Animate = new Animate(button);
* anim.propertyValuesList = [
* new PropertyValuesHolder("x", <a href="100%2C200">100,200</a>),
* new PropertyValuesHolder("y", <a href="100%2C150">100,150</a>)];
* anim.play();
* </listing>
*/
public class Animate extends Effect
{
public function Animate(target:Object = null) {}
//--------------------------------------------------------------------------
//
// Properties
//
//--------------------------------------------------------------------------
/**
* An array of PropertyValuesHolder objects, each of which holds the
* name of the property being animated and the values that the property
* will take on during the animation.
*/
public var propertyValuesList:Array;
/**
* The easing behavior for this effect. This IEaser
* object will be used to convert the elapsed fraction of
* the animation into an eased fraction, which will then be used to
* calculate the value at that eased elapsed fraction.
*
* @default spark.effects.Easing.Sine(.5)
* @see spark.effects.Easing.Sine
*/
public var easer:IEaser = defaultEaser;
/**
* The behavior of a repeating effect (an effect
* with <code>repeatCount</code> equal to either 0 or >1). This
* value should be either <code>Animation.LOOP</code>, where the animation
* will repeat in the same order each time, or <code>Animation.REVERSE</code>,
* where the animation will reverse direction each iteration.
*
* @default Animation.LOOP
* @see spark.effects.Animation#repeatBehavior
*/
public var repeatBehavior:String = Animation.LOOP;
/**
* This flag indicates whether the layout constraints (left, right, top,
* and bottom) should be adjusted when the effect ends, based on where
* the target has been positioned by the effect. This behavior can
* be useful for effects that change the position or size of a component
* during the course of running the effect, and when the desired result
* is that the target object stays in the resulting position without
* adjusting to the original constraints. For example, a Rotate effect
* run on a target with left/top constraints might otherwise be moved
* to the original constraint position, which has a different effect
* than rotating around a specified rotation center.
*
* <p>The default value
* is <code>false</code>, which means that the original constraints will
* be obeyed. To adjust the constraints based on the effect result,
* set this property to <code>true</code>.</p>
*
* @default false
*/
public var adjustConstraints:Boolean = false;
/**
* This property indicates whether the effect should disable layout on its
* targets' parents while the effect is running. If set to true, the effect
* will set the parent containers' <code>autoLayout</code> property to
* false for the duration of the effect. Note that other events may
* occur in those containers that force layout to happen anyway.
*
* @default false
*/
public var disableLayout:Boolean = false;
//--------------------------------------------------------------------------
//
// Methods
//
//--------------------------------------------------------------------------
/**
* By default, the affected properties are the same as those specified
* in the <code>propertyValuesList</code> array. If subclasses affect
* or track a different set of properties, they should override this
* method.
*/
override public function getAffectedProperties():Array {}
override protected function initInstance(instance:IEffectInstance):void {}
override protected function applyValueToTarget(target:Object, property:String,
value:*, props:Object):void {}
/**
* Called when the Animate dispatches an AnimationEvent.
* If you override this method, ensure that you call the super method.
*
* @param event An event object of type AnimationEvent.
*/
protected function animationEventHandler(event:AnimationEvent):void {}
}
/**
* The AnimateInstance class implements the instance class for the
* Animate effect. Flex creates an instance of this class when
* it plays a Animate effect; you do not create one yourself.
*/
public class AnimateInstance extends EffectInstance
{
public var animation:Animation;
public function AnimateInstance(target:Object) {}
//--------------------------------------------------------------------------
//
// Properties
//
//--------------------------------------------------------------------------
/**
* An array of PropertyValuesHolder objects, each of which holds the
* name of the property being animated and the values that the property
* will take on during the animation.
*/
public var propertyValuesList:Array;
/**
* This flag indicates whether values should be rounded before set on
* the targets. This can be useful in situations where values resolve to
* pixel coordinates and snapping to pixels is desired over landing
* on fractional pixels.
*/
protected var roundValues:Boolean;
/**
* This flag indicates whether the effect changes properties which are
* potentially related to the various layout constraints that may act
* on the object. Setting this to true will cause the effect to disable
* all standard constraints (left, right, top, bottom, horizontalCenter,
* verticalCenter) for the duration of the animation, and re-enable them
* when the animation is complete.
*/
protected var affectsConstraints:Boolean;
/**
* This flag indicates whether a subclass would like their target to
* be automatically kept around during a transition and removed when it
* finishes. This capability applies specifically to effects like
* Fade which act on targets that go away at the end of the
* transition and removes the need to supply a RemoveAction or similar
* effect to manually keep the item around and remove it when the
* transition completes. In order to use this capability, subclasses
* should set this variable to true and also expose the "parent"
* and "elementHost" properties in their affectedProperties array so
* that the effect instance has enough information about the target
* and container to do the job.
*/
protected var autoRemoveTarget:Boolean = false;
public var adjustConstraints:Boolean;
public var disableLayout:Boolean;
public function set easer(value:IEaser):void {}
public function get easer():IEaser {}
public function set interpolator(value:IInterpolator):void {}
public function get interpolator():IInterpolator {}
public function set repeatBehavior(value:String):void {}
public function get repeatBehavior():String {}
//--------------------------------------------------------------------------
//
// Overridden methods
//
//--------------------------------------------------------------------------
override public function pause():void {}
override public function stop():void {}
override public function resume():void {}
override public function reverse():void {}
/**
* Advances the effect to the specified position.
*
* @param playheadTime The position, in milliseconds, between 0
* and the value of the <code>duration</code> property.
*/
public function seek(playheadTime:Number):void {}
/**
* Interrupts an effect that is currently playing,
* and immediately jumps to the end of the effect.
* Calls the <code>Tween.endTween()</code> method
* on the <code>tween</code> property.
* This method implements the method of the superclass.
*
* <p>If you create a subclass of TweenEffectInstance,
* you can optionally override this method.</p>
*
* <p>The effect dispatches the <code>effectEnd</code> event.</p>
*
* @see spark.effects.EffectInstance#end()
*/
override public function end():void {}
//--------------------------------------------------------------------------
//
// Methods
//
//--------------------------------------------------------------------------
/**
* @copy spark.effects.IEffectInstance#startEffect()
*/
override public function startEffect():void {}
/**
* Starts this effect. Performs any final setup for each property
* from/to values and starts an Animation that will update that property.
*
* @private
*/
override public function play():void {}
/**
* Set the values in the given array on the properties held in our
* propertyValuesList array. This is called by the update and end
* functions, which are called by the Animation during the animation.
*/
protected function applyValues(value:Object):void {}
/**
* Handles start events from the animation.
* If you override this method, ensure that you call the super method.
*/
protected function startHandler(event:AnimationEvent):void {}
/**
* Handles update events from the animation.
* If you override this method, ensure that you call the super method.
*/
protected function updateHandler(event:AnimationEvent):void {}
/**
* Handles repeat events from the animation.
* If you override this method, ensure that you call the super method.
*/
protected function repeatHandler(event:AnimationEvent):void {}
/**
* Handles the end event from the animation. The value here is an Array of
* values, one for each 'property' in our propertyValuesList.
* If you override this method, ensure that you call the super method.
*/
protected function endHandler(event:AnimationEvent):void {}
/**
* Utility function that sets the named property on the target to
* the given value. Handles setting the property as either a true
* property or a style.
* @private
*/
protected function setValue(property:String, value:Object):void {}
/**
* Utility function that gets the value of the named property on
* the target. Handles getting the value of the property as either a true
* property or a style.
* @private
*/
protected function getCurrentValue(property:String):* {}
}
Move:
/**
* The Move effect changes the position of a component
* over a specified time interval.
* You can specify the initial position with the <code>xFrom</code> and
* <code>yFrom</code> values, the destination position with <code>xTo</code>
* and <code>yTo</code>, or the number of pixels to move the component
* with <code>xBy</code> and <code>yBy</code>.
*
* <p>If you specify any two of the values (initial position, destination,
* or amount to move), Flex calculates the third.
* If you specify all three, Flex ignores the <code>xBy</code> and
* <code>yBy</code> values.
* If you specify only the <code>xTo</code> and <code>yTo</code> values
* or the <code>xBy</code> and <code>yBy</code> values,
* Flex sets <code>xFrom</code> and <code>yFrom</code> to be the object's
* current position.</p>
*
* If used as an effect in a state transition, and the from/to/by values
* are left unspecified, then <code>Move</code> will infer the from/to values
* based on the information capture in the states.
*
* <p>You typically apply this effect to a target in a container
* that uses absolute positioning, such as Canvas,
* or one with <code>"layout=absolute"</code>, such as Application or Panel.
* If you apply it to a target in a container that performs automatic layout,
* such as a VBox or Grid container,
* the move occurs, but the next time the container updates its layout,
* it moves the target back to its original position.
* You can set the container's <code>autoLayout</code> property to <code>false</code>
* to disable the move back, but that disables layout for all controls in the container.</p>
*
* @mxml
*
* <p>The <code><mx:Move></code> tag
* inherits all of the tag attributes of its of its superclass,
* and adds the following tag attributes:</p>
*
* <pre>
* <mx:Move
* id="ID"
* xFrom="val"
* yFrom="val"
* xTo="val"
* yTo="val"
* xBy="val"
* yBy="val"
* />
* </pre>
*
* @see spark.effects.effectClasses.MoveInstance
*/
public class Move extends Animate
{
public function Move(target:Object=null) {}
//--------------------------------------------------------------------------
//
// Properties
//
//--------------------------------------------------------------------------
/**
* Number of pixels by which to modify the y of the component.
* Values may be negative.
*/
public var yBy:Number;
/**
* Initial y, in pixels.
* If omitted, Flex uses either the value in the start state,
* if the effect is playing in a state transition, or the current
* value in the target.
*/
public var yFrom:Number;
/**
* Final y, in pixels.
* If omitted, Flex uses either the value in the end state,
* if the effect is playing in a state transition, or the current
* value in the target.
*/
public var yTo:Number;
/**
* Number of pixels by which to modify the x of the component.
* Values may be negative.
*/
public var xBy:Number;
/**
* Initial x, in pixels.
* If omitted, Flex uses either the value in the starting state,
* if the effect is playing in a state transition, or the current
* value in the target.
*/
public var xFrom:Number;
/**
* Final x, in pixels.
* If omitted, Flex uses either the value in the starting state,
* if the effect is playing in a state transition, or the current
* value in the target.
*/
public var xTo:Number;
//--------------------------------------------------------------------------
//
// Overridden methods
//
//--------------------------------------------------------------------------
override public function getAffectedProperties():Array {}
override public function get relevantStyles():Array {}
override protected function initInstance(instance:IEffectInstance):void {}
}
Fade:
public class Fade extends Animate
{
public function Fade(target:Object=null) {}
//--------------------------------------------------------------------------
//
// Properties
//
//--------------------------------------------------------------------------
/**
* Initial transparency level between 0.0 and 1.0,
* where 0.0 means transparent and 1.0 means fully opaque.
*
* <p>If the effect causes the target component to disappear,
* the default value is the current value of the target's
* <code>alpha</code> property.
* If the effect causes the target component to appear,
* the default value is 0.0.</p>
*/
public var alphaFrom:Number;
/**
* Final transparency level,
* where 0.0 means transparent and 1.0 means fully opaque.
*
* <p>If the effect causes the target component to disappear,
* the default value is 0.0.
* If the effect causes the target component to appear,
* the default value is the current value of the target's
* <code>alpha</code> property.</p>
*/
public var alphaTo:Number;
//--------------------------------------------------------------------------
//
// Methods
//
//--------------------------------------------------------------------------
override protected function initInstance(instance:IEffectInstance):void {}
override public function getAffectedProperties():Array {}
override protected function applyValueToTarget(target:Object,
property:String,
value:*,
props:Object):void {}
}
Resize:
Note: The hideChildrenTargets functionality is currently disabled due to an unrelated change to remove the Panel object from the new components and should be re-thought in general
public class Resize extends Animate
{
public function Resize(target:Object=null) {}
//--------------------------------------------------------------------------
//
// Properties
//
//--------------------------------------------------------------------------
/**
* Number of pixels by which to modify the height of the component.
* Values may be negative.
*/
public var heightBy:Number;
/**
* Initial height, in pixels.
* If omitted, Flex uses the current height.
*/
public var heightFrom:Number;
/**
* Final height, in pixels.
*/
public var heightTo:Number;
/**
* Number of pixels by which to modify the width of the component.
* Values may be negative.
*/
public var widthBy:Number;
/**
* Initial width, in pixels.
* If omitted, Flex uses the current width.
*/
public var widthFrom:Number;
/**
* Final width, in pixels.
*/
public var widthTo:Number;
/**
* An Array of Panel containers.
* The children of these Panel containers are hidden while the Resize
* effect plays.
*
* <p>You use data binding syntax to set this property in MXML,
* as the following example shows, where panelOne and panelTwo
* are the names of two Panel containers in your application:</p>
*
* <pre><mx:Resize id="e" heightFrom="100" heightTo="400"
* hideChildrenTargets="{<a href="panelOne%2C%20panelTwo">panelOne, panelTwo</a>}" /></pre>
*/
public var hideChildrenTargets:Array /* of Panel */;
override public function getAffectedProperties():Array {}
override public function get relevantStyles():Array {}
override protected function initInstance(instance:IEffectInstance):void {}
}
Rotate:
/**
* The Rotate effect rotates a component around a specified point.
* You can specify the coordinates of the center of the rotation,
* and the starting and ending angles of rotation.
* You can specify positive or negative values for the angles.
*
* <p>If you specify any two of the angle values (angleFrom, angleTo,
* or angleBy), Flex calculates the third.
* If you specify all three, Flex ignores the <code>angleBy</code> value.</p>
*
* <p><b>Note:</b> To use the Rotate effect with text,
* you must use an embedded font, not a device font.</p>
*
* @see spark.effects.effectClasses.RotateInstance
*/
public class Rotate extends Animate
{
public function Rotate(target:Object = null) {}
//--------------------------------------------------------------------------
//
// Properties
//
//--------------------------------------------------------------------------
/**
* The starting angle of rotation of the target object,
* expressed in degrees.
* Valid values range from 0 to 360.
*/
public var angleFrom:Number;
/**
* The ending angle of rotation of the target object,
* expressed in degrees.
* Values can be either positive or negative.
*
* <p>If the value of <code>angleTo</code> is less
* than the value of <code>angleFrom</code>,
* the target rotates in a counterclockwise direction.
* Otherwise, it rotates in clockwise direction.
* If you want the target to rotate multiple times,
* set this value to a large positive or small negative number.</p>
*/
public var angleTo:Number;
/**
* Degrees by which to rotate the target object. Value
* may be negative.
*
* <p>If the value of <code>angleBy</code> is negative,
* the target rotates in a counterclockwise direction.
* Otherwise, it rotates in clockwise direction.
* If you want the target to rotate multiple times,
* set this value to a large positive or small negative number.</p>
*/
public var angleBy:Number;
/**
* The x-position of the center point of rotation.
* The target rotates around this point.
* The valid values are between 0 and the width of the target.
* If this property is not set, the effect will automatically set
* the origin to be at the center of the target object.
*/
public var originX:Number;
/**
* The y-position of the center point of rotation.
* The target rotates around this point.
* The valid values are between 0 and the height of the target.
* If this property is not set, the effect will automatically set
* the origin to be at the center of the target object.
*/
public var originY:Number;
//--------------------------------------------------------------------------
//
// Overridden methods
//
//--------------------------------------------------------------------------
override public function getAffectedProperties():Array {}
override protected function initInstance(instance:IEffectInstance):void {}
}
AnimateColor:
This effect is the first (of those listed) to use the interpolator capability of Animation. It internally creates a ColorInterpolator object which it supplies to the underlying Animation so that the from/to colors are interpolated correctly.
/**
* This effect animates a change in color over time, interpolating
* between given from/to color values on a per-channel basis.
*/
public class AnimateColor extends Animate
{
/**
* The starting color
*/
public var colorFrom:uint;
/**
* The ending color
*/
public var colorTo:uint;
/**
* The name of the color property on the target object affected
* by this animation.
*
* @default "color"
*/
public var colorPropertyName:String = "color";
public function AnimateColor(target:Object=null) {}
override public function getAffectedProperties():Array {}
override public function get relevantStyles():Array {}
override protected function initInstance(instance:IEffectInstance):void {}
}
CallAction:
All of the effects above subclass from the new Animate class, as opposed to the TweenEffect class that the Halo effects subclass from. The Action effects of Halo subclass directly from Effect (they do not need the animation capabilities of TweenEffect). I am also adding one additional Action effect, CallAction, which also subclasses directly from Effect. The above discussions of Animate do not apply here, but I include this new effect for completeness since it is also new in Gumbo.
/**
* This effect, when played, calls the function specified by
* <code>functionName</code> on the <code>target</code> object with
* optional <code>parameters</code>. The effect may be useful in
* effect sequences where some function call can be choreographed
* with other effects.
*
* @see spark.effects.effectClasses.CallFunctionActionInstance
*/
public class CallAction extends Effect
{
public function CallAction(target:Object = null) {}
//--------------------------------------------------------------------------
//
// Properties
//
//--------------------------------------------------------------------------
/**
* Name of the function that will be called on the target when this effect plays
*/
public var functionName:String;
/**
* Parameters that will be supplied to the function that is called
* by this effect
*/
public var parameters:Array;
//--------------------------------------------------------------------------
//
// Overridden methods
//
//--------------------------------------------------------------------------
override protected function initInstance(instance:IEffectInstance):void {}
}
Follow-on work from this feature will include other effects (ported over from the old effects or new), and would expose similar API. Examples of future effects include Bitmap effects that will use Pixel Bender shaders to transform before/after bitmaps.
1) Shorter syntax for triggering effects
It is worth exploring whether we can expose the 'trigger' functionality through a short-hand approach in MXML. The above method (in PropertyAnimator) would mean that callers must start event-based effects with something like this:
<Move id="myMove"/>
< Button move="myMove.trigger(event)"/>
We may want to enable this functionality through a more terse syntax (much like the current "Triggers"), where the following MXML could be used in place of the code above:
< Button move="Move"/>
Note: Triggers are not implemented yet in the new effects, as the syntax and functionality desired are not yet determined.
2) Motion along a path
This is probably a separate feature altogether, but I mention it here for completeness. With the structures described above for associating a property name with a list of values, it becomes possible to use that approach to define more complex motion paths. For example, we could also allow PropertyValuesHolder to have an item that specifies how to interpret the list of values, such as VALUES_CUBIC, and then derive a curved path that the object follows during the animation.
3) Keyframes
As with (2) above, we could allow the values list in PropertyValuesHolder to hold an arbitrary list of values and then supply a list of time values when those values hold true, thus providing a set of keyframes to the effect. I believe this is necessary and desirable functionality in a robust animation system, although it will probably not make this release.
Use of the Move and Fade effects above are similar to how they are used today, both from ActionScript and MXML. For example, the Move effect could be started automatically by a transition through this MXML code, which automatically takes the from/to parameters from a combination of the state values and the current target location:
<transitions>
<Transition>
<Move id="myMove" target="{button}"/>
</Transition>
</transition>
<Button id="button"/>
You could also specify specific parameters for the effect like this:
<MoveXY id="myMove" xFrom="100" xTo="200" yFrom="50" yTo="150"/>
You could also have the button manually start the transition like this:
<Button id="button" click="myMove.play()"/>
Note that the xFrom/yFrom/etc. attributes of Move (like attributes of other effects) are shorthands for setting the properties/values of the Animate effect superclass directly. This improves the MXML code for these effects, as setting Arrays in MXML ends up in a lot of angle-brackets. Nevertheless, it is possible to do this in MXML for any effect. For example, here is how one would set up a Move-like effect in MXML by using the Animate effect directly:
<Declarations>
<Animate id="mover">
<PropertyValuesHolder property="x" values="{<a href="0%2C100">0,100</a>}"/>
<PropertyValuesHolder property="y" values="{<a href="0%2C100">0,100</a>}"/>
</Animate>
</Declarations>
<Button id="button" click="mover.play(<a href="button">button</a>)"/>
The Animate class is a bit different than current effects because it allows specification of multiple values through its propertyValuesList property. In ActionScript code, this is what it would look like to animate several properties on a target object simultaneously:
var zoomer:Animate = new Animate(shape);
zoomer.propertyValuesList = [
new PropertyValuesHolder("x", <a href="shape.x%2C%20shape.x%20-%20100">shape.x, shape.x - 100</a>),
new PropertyValuesHolder("y", <a href="shape.y%2C%20shape.y%20-%20100">shape.y, shape.y - 100</a>),
new PropertyValuesHolder("width", <a href="1%2C%20200">1, 200</a>),
new PropertyValuesHolder("height", <a href="1%2C%20200">1, 200</a>),
new PropertyValuesHolder("alpha", <a href="1%2C%200">1, 0</a>)];
zoomer.duration = DURATION;
zoomer.play();
It is generally expected that common effects, especially those instantiated in MXML, would be accessed through subclasses of Animate and would (like Move, Fade, and Resize) have helper properties that are less verbose to set up than the propertyValuesList property of Animate.
The trick with this feature is making the mechanisms of transitions and triggers work well with the new effects. So far, the transitions capabilities all work successfully in the new effects. In fact, the new effects handle transitions somewhat more easily than the old effects. For example, Fade can now fade objects in or out automatically depending on states' alpha, visible, or parented properties; the old effects relied on helper effects such as RemoveChildAction to do this successfully.
Meanwhile, effect triggers do not work on the new effects. To some extent, the problem is made difficultby our more generic approach to setting properties on targets. Previously, we would call specific functions on the targets. These targets could, for example, avoid dispatching events when necessary, which avoided potential recursive situations like triggering a Move effect while changing x and y because of a Move effect. But also, we are considering not implementing triggers simply because there are already ways to achieve that functionality, via transitions and calling play() directly.
The effects listed above in the "API Description" section are all working and checked in. Some prototype work has been done in the area of effect triggers, should we decide that we do want them to work on the new effects, but otherwise we are simply implementing new effects and functionality as we get to it.
The B Feature item above, "Shorter syntax for triggering effects" may require some compiler work to turn the terse MXML syntax into the full ActionScript code required.
None
This feature depends on the "Arbitrary Type Interpolation" feature, specifically to enable AnimateColor. That feature is complete and the code is checked in already.
These effects will be new classes, so previous effects will not have any API implications. The API for these new effects will differ slightly from the old effects (such as "triggers" going away as a concept on Gumbo components), but again this is for new classes (effects and components), and should not cause a problem with the current APIs.
None. "Triggers" will go away with the new effects, but will still work on UIComponent subclasses and the old effects.
N/A - we are just setting properties on accessible components (and other objects), not affecting how that accessibility works
As with other animation operations, we will need to ensure that performance is good enough to provide a smooth animation experience. This might mean updating the screen after processing Animation events, avoiding unnecessary overhead during animating, and otherwise ensuring lightweight animation.
N/A
N/A
There will be Errors thrown from bad parameters, but otherwise no use of Strings.
Trigger functionality: I have done enough prototyping to know how to enable trigger-like functionality for the simple effects of Move and Fade, but I don't know yet whether there are other, harder situations to account for in how these new effects are set up, run, and ended.
Note: Triggers, and whether we want them implemented for these effects, are TBD
I am currently adding these effects as new classes. We could, and maybe should, consider merging this functionality into the existing Effects classes, simply broadening their functionality to work as before and also with new components and arbitrary objects. This merge would involve changing their behavior and API (for example, the new system depends on Animation, not Tween, and the new system sets properties directly without calling functions), so it it's not an easy choice. The tradeoff here is increased and somewhat redundant API vs. potentially altered behavior for existing API.
None, other than documenting the new classes and the new use of effects on arbitrary objects.