Reversal: In the context of this spec, 'reversal' means the ability for transition effects to reverse and play backwards. This includes the capability of being able to declare a transition as being reversible (so that developers do not have to declare both directions explicitly) as well as the ability for a transition to stop and reverse on the fly, when running back to the state they were animating from.
One of the more difficult aspects of using transitions in Flex is that interrupting transitions and going to different states can cause disruptive behavior. Because Flex cannot currently play multiple effects simultaneously (or, to be more specific and correct, cannot play multiple effects that operate on the same targets/properties without artifacts), the transition engine simply ends any currently-running transition effect before launching the new ones. The process of ending the previous transition effect causes the effect to snap the targets to their end locations, which causes sudden and disturbing movement before the new animation begins.
The purpose of this feature is to enable more functionality and API that enables transitions to smoothly move between different transition effects.
Users could set properties on transitions that tell the system what behavior they should have at runtime. For example, a property of 'autoReverse' might be used to denote that a transition should reverse on the fly when its reverse transition interrupts it.
In the case of reversing, or playing new transition effects that are returning to the state currently being animated from (a common occurrence), it should be possible to stop the current transition where it is and start the new, reversing transition from that point.
It should also be possible to move more smoothly between separate transitions, even if they are not reversals of each other. For example, if there is a transition playing between states A and B and a user action causes a change to state C, then instead of ending the first transition (which places it in state B), we could stop the transition effect where it is and start the transition to C from that point. This could be optional behavior, as determined by some code-settable property of the transition.
It should also be easier to declare a transition as being 'reversible', which would save code and effort from declaring multiple transitions that are simply inverses of each other. Currently, when you want to declare a transition (e.g., <fade>) from state A to B and the same/opposite transition from B to A, you have to declare two separate transitions, each with the same (or opposite) innards. The SDK should make it easier to declare a transition as being reversible, which would denote that when there is a state change in the opposite direction to that declared for the transition, then we would simply play this same transition in reverse.</fade>
Most of this feature is implemented under the hood: tracking the states being transitioned from/to, figuring how how much time has elapsed on current transitions and how to fast-forward to the appropriate place in the new transition, etc. All of the API necessary is to enable one of two things:
Addition to mx.states.Transition:
/**
* Whether the transition should automatically reverse itself
* when the opposite state transition begins playing.
*
* <p>Flex does not currently play multiple transitions simultaneously.
* This means that when a new state transition occurs, if there
* is already one playing it is stopped by calling <code>end()</code>
* on it, which snaps it to its end values. The new transition
* then starts playing from that state.</p>
*
* <p>The <code>autoReverse</code> flag allows the developer to
* control whether the default snap-to-end behavior occurs, or whether,
* instead, the previous effect is stopped in place and the new
* effect is played from that intermediate state instead. Internally,
* the transition code calculates how much of the previous effect
* has been played and then plays the next effect for the inverse of that
* time.</p>
*
* <p>This flag is only checked when the new transition is going in the
* exact opposite direction of the currently playing one. That is, if
* a transition is playing between states A and B and then a transition
* to return to A is started, this flag will be checked. But if the
* application is going from state A to B and a transition to state C is
* started, then the default behavior of snapping to the end of the A->B
* transition, then playing the B->C transition will occur.</p>
*
* @default false
*/
public var autoReverse:Boolean = false;
Additions to Effect and EffectInstance:
/**
* Sets the current time of an effect. Seek may be used to
* fast-forward or reverse to a particular point in time in an effect.
*
* @param seekTime Number of milliseconds that the effect should
* play at. This number should be between 0 and the duration of the
* effect.
*
* @see #duration
*/
function seek(seekTime:Number):void;
/**
* Current position in time of the effect.
* This property has a value between 0 and the actual duration
* (which includes the value of the <code>startDelay</code>,
* <code>repeatCount</code>, and <code>repeatDelay</code> properties).
*/
function get playheadTime():Number;
In CompositeEffect (and overridden in Parallel and Sequence):
/**
* Returns the duration of this effect as defined by the duration of
* all child effects. This takes into account the startDelay and repetition
* info for all child effects, along with their durations, and returns the
* appropriate result.
*/
public function get compositeDuration():Number{}
Although 'interruption' is part of this feature, the most important part at first is being able to reverse animations on the fly. Figuring out what to do to interrupt one transition and then start another one is more complicated, and involves more options. This puts it on the B list for me: I'd like to get to it, but there are probably more pressing features for Flex that I need to handle first.
Were I to tackle interruption in general, I would probably provide various options, selectable by a property on the transition. For example, in discussion with Ely, here are some options that have come up: - The current behavior (jump to the end of the previous transition, play the new one from there) - Stop&play (stop at the current point of the previous transition and play the new one from there) - autoReverse (the A feature described above, specific to cases where the new transition is the reverse of the previous one) - forceComplete (finish the previous transition, then possibly play the next transition from that point, unless another transition occurred in the meantime)
Note to self: One of the hold-ups on implementing this B feature is the interaction of transitions and state values. Currently, states without explicit values for properties will derive those values on the fly from whatever the property value is. This means that if we short-circuit a transition, such as stopping it in place to take on one of the behaviors above, then we will essentially clobber the values of properties that have no explicit declaration for that state. If there is a simple workaround for this situation, that would simplify this part of the feature.
Currently, a user must declare reverse transitions explicitly. If they want a <move> when going from state1 to state2 and the same effect when going from state2 to state1, they must supply two transitions that look exactly the same except for the fromtState/toState properties on Transition. For more complicated effects, like a Parallel effect with many effect children, they must figure out the reverse order for the effects and create a reversed transition appropriately.</move>
The SDK could figure this out for the user, making it necessary for them to only declare one direction and then, through the use of some transition flag presumably (e.g., <transition reversible="true">), tell us to calculate the inverse transition for them. Then, when we encounter a state-state transition that is the reverse of one declared, we will use this calculated inverse automatically.</transition>
Although it is possible for the SDK to do this, it is not a simple task, thus this is a B Feature as there are probably more pressing feature to implement (at least there is a workaround for this feature; developers continue to explicitly declare the reverse transitions they require). Note, for example, that it is not as simple as just playing a transition in reverse: you still want each atomic effect to play from/to the states in question, and not to play in reverse from the "to" state to the 'from" state. This complicates the implementation since we can't just play stuff backwards; we have to take different approaches in different situations.
It is worth noting some of the elements that would have to be addressed in implementing this feature:
An example of two Parallel transition effects which reverse on the fly when opposite state changes occur mid-transition:
<Transition fromState="State1" toState="State2" autoReverse="true">
<Parallel>
<FxResize adjustConstraints="true" targets="{<a href="rect4">rect4</a>}" duration="1000"/>
<FxFade target="{rect5}" duration="300" startDelay="1000"/>
<FxFade target="{rect6}" duration="300" startDelay="1300"/>
<FxFade target="{rect7}" duration="300" startDelay="1600"/>
<FxFade target="{rect8}" duration="300" startDelay="1900"/>
</Parallel>
</Transition>
<Transition fromState="State2" toState="State1" autoReverse="true">
<Parallel>
<FxFade target="{rect8}" duration="300"/>
<FxFade target="{rect7}" duration="300" startDelay="300"/>
<FxFade target="{rect6}" duration="300" startDelay="600"/>
<FxFade target="{rect5}" duration="300" startDelay="900"/>
<FxResize adjustConstraints="true" targets="{<a href="rect4">rect4</a>}" duration="1000" startDelay="1200"/>
</Parallel>
</Transition>
Similarly, a Sequence effect that has the same behavior:
<Transition fromState="State1" toState="State4" autoReverse="true">
<Sequence>
<FxResize adjustConstraints="true" targets="{<a href="sequenceRect">sequenceRect</a>}" duration="1000"/>
<AddAction target="{rect5s}"/>
<FxFade target="{rect5s}" duration="300"/>
<AddAction target="{rect6s}"/>
<FxFade target="{rect6s}" duration="300"/>
<AddAction target="{rect7s}"/>
<FxFade target="{rect7s}" duration="300"/>
<AddAction target="{rect8s}"/>
<FxFade target="{rect8s}" duration="300"/>
</Sequence>
</Transition>
<Transition fromState="State4" toState="State1" autoReverse="true">
<Sequence>
<FxFade target="{rect8s}" duration="300"/>
<RemoveAction target="{rect8s}" effectEnd="removeEndHandler()"/>
<FxFade target="{rect7s}" duration="300"/>
<RemoveAction target="{rect7s}"/>
<FxFade target="{rect6s}" duration="300"/>
<RemoveAction target="{rect6s}"/>
<FxFade target="{rect5s}" duration="300"/>
<RemoveAction target="{rect5s}"/>
<FxResize adjustConstraints="true" targets="{<a href="sequenceRect">sequenceRect</a>}" duration="1000"/>
</Sequence>
</Transition>
This initial work on the feature is expected to hit the high points and fix the critical problems in this area. It is possible that later work may be required to round out the feature or add other nice-to-haves. For example, seeking behavior on composite animations is expected to work to the extent necessary for this feature, although there may be bugs in the general functionality of seeking that may not be fixed at this time.
The basic behavior and API around auto-reversing simple and complex animations is mostly done at this time. The functionality of auto-reversing Parallel animations was done for the alpha release. This exposed some API that has since changed and there were various implementation details that also changed. The new work in i9 includes this capability for Paralle effects, but adds the capability of reversing Sequence animations as well.
The additional work of interrupting effects and playing different transitions (not simple reverses) is not yet prototyped. Some initial work in stopping animations was done, but this approach does not work well with states, so there should probably be a different implementation for robust behavior. Also, the API around interrupting and starting new transitions requires more thought.
None
None
None
None
Action effects need to have zero duration to make composite effect duration calculation correct. This is a behavior change (these effects previously had the default duration), but it is doubtful that anyone ever set or queried this property on the Action effects, since the property was ignored in these Effect subclasses.
None
None
None
None
None
None
None
None
Capabilities should be tested with both complex (Parallel and Sequence) and simple (non-composite) effects. Ensure that reversing animations start from the same place (or close to it) that the previous transition ended. Note that this feature requires that reversing transitions be of the same overall duration, and be functionally reversals of each other, otherwise the effects may be undesirable.