- Using Transitions to Simplify JavaFX Animations
- The Transition Superclass
- Basic Transitions
- Basic Transitions, Continued
- Compound Transitions
- Creating Additional Transitions
- Conclusion
Creating Additional Transitions
The aforementioned transitions will probably meet your needs. Then again, you might need a transition that's currently not implemented. For example, you might need a transition that animates a node's drop-shadow effect. If you need to create a new transition, you must first learn about the following Transition variables and function:
- parent (of type Transition) identifies the parallel, sequential, or other compound Transition to which this Transition has been added. This protected variable defaults to null.
- timeline (of type Timeline) is an internal Timeline that is created when this Transition is created. This protected variable controls Transition operations such as play() and pause().
- timelineDirty (of type Boolean) indicates whether the internal Timeline (as specified via the timeline variable) needs to be rebuilt. This protected variable, when set to true (the default), indicates that the Timeline must be rebuilt.
- UNDEFINED (of type Number) specifies a value that doesn't map to a value used in animating the node. This protected variable indicates that a Number variable has not been initialized or manipulated by user code.
- protected getTargetNode(): Node returns the value of this Transition's node variable if not null, or returns the parent variable's node value if parent and node are not null; otherwise, it returns null.
I've reverse-engineered the FadeTransition class to show you how it uses these variables and getTargetNode() to fade a node's opacity. You can use the resulting source code (shown in Listing 8) as a starting point for creating your own transitions. My decompiler reports that this source code creates the same Java bytecodes (with some method reordering) as the bytecodes found in Sun's version of this class.
Listing 8FadeTransition implementation.
class FadeTransition extends Transition { public var fromValue = UNDEFINED on replace { timelineDirty = true } public var toValue = UNDEFINED on replace { timelineDirty = true } public var byValue = UNDEFINED on replace { timelineDirty = true } function build (): Void { var myNode = getTargetNode (); var fV = if (fromValue == UNDEFINED) myNode.opacity else fromValue; var tV = if (byValue == UNDEFINED) fV else fV+byValue; tV = if (toValue == UNDEFINED) then tV else toValue; var keyFrames: KeyFrame[]; insert at (0ms) { myNode.opacity => fV tween interpolate } into keyFrames; insert KeyFrame { time: duration values: [ myNode.opacity => tV tween interpolate ] action: function (): Void { action () } } into keyFrames; timeline.keyFrames = keyFrames; timelineDirty = false } public override function play (): Void { if ((not running) and ((fromValue == UNDEFINED) or timelineDirty)) build (); super.play () } public override function playFromStart (): Void { if ((not running) and ((fromValue == UNDEFINED) or timelineDirty)) build (); super.playFromStart () } }
Listing 8 refers to each of the previous list's members except for parent. For this transition, parent doesn't need to be accessed directly; it's accessed from within getTargetNode(). In contrast, ParallelTransition and SequentialTransition, which don't invoke this function, explicitly access parent.