JavaFX gives you three different ways to run animations in your application. Which one you choose will depend on what you’re trying to animate.

In this article, I wanted to give you a resource on how to use each type of animation, but also about how to choose which animation you use as well. This article goes through how to use each object as well as how to get the most out of them.

Here are what I think are the relative strengths and weaknesses of each of the animation types.

TypeControlsStrengthsLimitations
TransitionNodes– Targets elements of the scene graph.
– Extensible interpolation.
You can only use them on nodes.
In some cases, you’re limited shapes
TimelineWriteableValue objects like JavaFX properties– Multiple properties in the same animation.
– More complex animations
– Extensible interpolation.
Fairly heavy-weight animation object
AnimationTimerNone– Direct access to the timestamp of the pulseNo default interpolation

What you’ll get from this article

A lot of functionality is common to Transitions and Timelines – from the number of times they play, to how the animation interpolates the values. I’ll run through the common features first, so we don’t have to cover them twice.

Then, I’ll take you through the specifics of how to create and use Transition, Timeline and AnimationTimer objects in detail. If you need the specifics now, feel free to jump ahead.

By the end of this article, you should be able to create animations and fire events from them. You’ll be able to change object properties and change how animations interpolate between those values. Finally, you’ll understand how animations work – so when you need to extend that functionality, you’ll have a good basis from which to start.

JavaFX Animations

All of these animations work by listening to an animation pulse that JavaFX sends out once per frame (default frame rate is 60 Hz). Then, every animation decides what to do with that information based on its function.

For animation timers, the only function is to run its one method. For more complex animations, the timestamp is converted into the proportion of the animation that’s already passed, and that result is used to update the animation value.

The frame rate of animations can vary, both from system to system, and based on the CPU load your computer’s under.

And finally, JavaFX is structured so that the two types of animation – Timeline and Transition – inherit from a higher Animation object. That means there are a lot of features common to every animation in JavaFX. I’ll cover them here before covering the specifics of each type further down.

Common features of every animation

There are seven features that are common between every JavaFX animation:

  • Cycle count (how many times an animation plays),
  • An animation delay (i.e. the time between pressing play and it beginning),
  • Auto-reverse,
  • Rate,
  • The ability to “jump” to a point in an animation,
  • Firing events once an animation is complete, and
  • Interpolation

Open up whatever you need, otherwise feel free to move on to the specifics of how to create animations.

Play more than once (cycle count)

Every animation in JavaFX has a cycle count, which means it can be repeated any number of times. You can set this feature using the setCycleCount() method, which accepts an integer number of cycles.

If you want the animation to keep playing indefinitely, invoke setCycleCount(), passing the convenience variable Animation.INDEFINITE. Once started, your animation to play until stopped.

FadeTransition fadeTransition = new FadeTransition();
fadeTransition.setCycleCount(Animation.INDEFINITE);

Interpolation

Interpolation is the way an animation moves the value of the property its changing between the two set points you’ve given it. And, even though the Animation class itself doesn’t use interpolation, both the Timeline and Transition classes make use of it, so I wanted to cover it more generally here.

I’m not even going to squeeze interpolation into an option drop-down, because I think it’s really important to understand how powerful it can be. You can literally use interpolation to simplify your animations – using fewer transition objects and key frames to achieve the same result.

You can either use the pre-defined interpolators, or you can create your own. The Interpolator class is an abstract class with a single abstract method curve(). This converts the proportion of the animation that’s already passed into the proportion the value should have changed since the last frame.

Predefined Interpolators

JavaFX gives you five default interpolators: linear, discrete, ease-both, ease-in and ease-out. All Transition animations by default use ease-both to give the animation a smooth feel. All Timeline animations by default use linear.

Creating Animations

JavaFX gives you three types of class to support animation out-of-the-box: transition, timeline and animation timers. They’re all different, and fundamentally I’d break them down like this by:

  • What’s they’re designed to do
  • What values they can change by default
  • What sort of animation complexity you can generate

Here’s a breakdown one by one:

TypeDesign intentionValues it can changeComplexity
TransitionSmoothly change scene-graph properties like size, opacity and rotation.Properties of Node objects (some specific to Shape)Define single transitions. Combine using utility classes.
TimelineComplex animations of groups of values requiring more precision.Any WriteableValue (e.g. JavaFX properties)Define multiple key frames to animate sets of values at each.
AnimationTimerDirect access to the timestamp of the animation frameNo values changedDeveloper handles implementation

In each of the next three sections, I’ll go through each animation type and how to use them.

Transitions

A transition is an animation designed to alter specific visible properties of nodes in a scene graph. For more complex transformations, you can combine multiple transitions by nesting them inside ParallelTransition and SequentialTransition objects.

You can also change the interpolation, which is how the value changes between the numbers you’ve set.

The default interpolator for any Transition is Interpolator.EASE_BOTH. If you want to change the interpolator, invoke setInterpolator(), passing in the Interpolator object you need.

There are eight Transition classes in JavaFX, which support updating the appearance and transforms of nodes within a scene. Additionally, the ParallelTransition and SequentialTransition objects can be used to combine transitions.

Appearance Transitions

JavaFX is really well set-up to handle animations for Shape objects. If you’re trying to animate a Shape, you have access to the FadeTransition, the FillTransition, and StrokeTransition,

But I’m going to level with you – if you want to change the properties of a Region, or Pane, you only have access to the FadeTransition. That’s because Fill and Stroke are easy to change in Shapes, and much more complex to implement in nodes.

FadeTransition

The FadeTransition animation is used to animate the opacity of a Node. Both the border and background are affected.

The FadeTransition animation is used to animate the opacity of a Node. Both the border and background are affected.

To fade out a node completely, regardless of its current opacity, use the fading from a value by a specific amount approach, setting the byValue to -1.

FadeTransition fadeTransition = new FadeTransition(Duration.millis(500), myNode);
fadeTransition.setByValue(-1);
fadeTransition.play();
FillTransition

The FillTransition animation is used to animate the colour of a Shape node’s inner area (or fill). The transition will smoothly interpolate red, green and blue values associated with the fromValue color (default is the current color of the Shape) to the toValue color.

The FillTransition animation is used to animate the colour of a Shape node's inner area (or fill).

Because this is such a simple animation, the interpolation from the fromValue to the toValue can take you through colors that don’t make the animation that appealing. In that case, you can create multiple color transitions and combine them using a SequentialTransition animation.

This transition has one of the richest sets of constructor options. It won’t work unless you define a Shape, but you can create the transition and define one later. If you don’t define the fromValue, the transition will use the current color. Equally, if you don’t define a duration, the transition will use the default value of Duration.millis(400).

FillTransition()
FillTransition​(Duration duration)
FillTransition​(Duration duration, Color fromValue, Color toValue)
FillTransition​(Duration duration, Shape shape)
FillTransition​(Duration duration, Shape shape, Color fromValue, Color toValue)
StrokeTransition

The StrokeTransition animation is used to animate the colour of a Shape node’s border (or stroke). This is similar to the FillTransition in all of the options you can specify, varying only by the fact that this will effect the outline of an object, but not its fill.

The StrokeTransition animation is used to animate the colour of a Shape node's border (or stroke)

Again, you can define this transition with no parameters, but to see an effect, you’ll need to define the Shape and the toValue as an absolute minimum.

StrokeTransition()
StrokeTransition​(Duration duration)
StrokeTransition​(Duration duration, Color fromValue, Color toValue)
StrokeTransition​(Duration duration, Shape shape)
StrokeTransition​(Duration duration, Shape shape, Color fromValue, Color toValue)

Transform Transitions

In JavaFX, the three basic transforms are translation, rotation and scale. Each of these is supported by a Transition object, which provides a useful, minimal implementation to handle smoothly changing the transforms of a JavaFX Node.

There aren’t any transitions for more complex transforms such as skewing, although you could make one (the Transition object is fairly easy to extend).

Finally, the PathTransition is an interesting composite Transition, which can move objects in much more complex shapes. It can also optionally update the rotation of an object as it completes this movement.

I’ll go through each of the transitions in turn and how to use them.

TranslateTransition

The TranslateTransition animation is designed to animate the position of a node within its parent. When JavaFX renders a node to the screen, it will factor into this calculation both the layout position and translate modification, meaning nodes can be positioned and animated separately.

If a start position for the animation is not specified, the animation will start from the current node position. The end position is then calculated either by using the to-properties (which define the end position), or using the by-properties (byX, byY, byZ), which define the size and direction of the movement. If both are specified, the to-properties will be used and the by-properties will be ignored.

The TranslateTransition animation is used to animate the position of nodes

Just be aware that once you start changing the translateX, translateY and translateZ the position is a combination translate coordinates and the layout position. Generally, JavaFX was designed to use translate properties for fine adjustments and animation rather than absolute positioning.

If you create a TranslateTransition without parameters, the default duration will be 400 milliseconds. You can define the Node during construction. All other parameters need to be defined using the setter methods for each property.

TranslateTransition();
TranslateTransition​(Duration duration);
TranslateTransition​(Duration duration, Node node);
RotateTransition

The RotateTransition animation is used to animate the rotation angle of a node. The angles defined for this animation must be specified in degrees, rather than radians.

If a start angle is not provided for the animation, the rotation will begin at the current values of the node. As with the translate transition, the end of the rotation can be defined either using the byAngle or the toAngle properties, with toAngle taking precedence.

The RotateTransition animation is used to animate the rotation angle of nodes

I’ve only shown this in two dimensions, but of course JavaFX has fantastic support for 3D animations too.

To enable rotation in three dimensions, you’ll need to specify the rotation axis. Nodes already have a rotationAxis property. That means you can either specify the axis on the node directly, or using the transition object. When you specify the rotation axis in the RotateTransition, all it does is change the node’s rotationAxis property anyway!

As always, if you create a RotateTransition without parameters, the default duration will be 400 milliseconds. You can define the Node during construction. All other parameters need to be defined using the setter methods for each property.

RotateTransition();
RotateTransition​(Duration duration);
RotateTransition​(Duration duration, Node node);
ScaleTransition

The ScaleTransition animation is used to animate the size of a node. By specifying the start (optional) and end, or increase values, you can produce smooth animations in the size of part of the scene graph.

A note on scaling behaviour: Because scaling is usually multiplicative (if you have a scale of 2, you’ll get something two times as big), you might think that this would be how byX, byY and byZ properties work. Just be warned they don’t!

If your fromX value is 1 (it’s the right size), and your byX value is 1, the two are added together (not multiplied) to get a final scale value of 2.

So, to shrink things, you will need to use negative numbers (not decimals like 0.5 as you might think).

As with other transitions, the toX, toY and toZ properties will override any byX, byY and byZ values that have been set.

If you create a ScaleTransition without parameters, the default duration will be 400 milliseconds. As always, to make it work, you’ll have to give it a Node and some from-properties to see a visible change in the scene.

ScaleTransition();
ScaleTransition​(Duration duration);
ScaleTransition​(Duration duration, Node node);

Just remember, because you’re scaling your node, the scaling will also be applied to children. This transition doesn’t change the size of the node in terms of width and height (although they will visibly change). It alters the scaling factor that’s applied to the node – and all of the node’s children.

PathTransition

The PathTransition animation is used to animate the location of objects over more complex paths. It can optionally be used to alter the rotation too, by setting the Orientation property to ORTHOGONAL_TO_TANGENT. This makes the y-axis of the shape line up with the direction of the path the object is following.

The PathTransition animation is used to animate the location of objects over more complex paths. It can optionally be used to alter the rotation too.

A note on translation and rotation: Later on, I’ll go through ways to combine transitions. Just be aware that the PathTransition doesn’t do anything special when it comes to moving your object – it just updates the translate and rotate values.

When I tested this, if you try and combine it with a rotate or translate animation in a ParallelTransition, the animation displayed currently favours the transition you’ve registered last – presumably because the current implementation updates the values in that order. That’s not guaranteed to stay unchanged, though, so try not to combine conflicting animations.

As with other transitions, the PathTransition can be created with no parameters, but it won’t do anything. To make it work, you’ll need to define a Path object, and the Node as a minimum.

PathTransition();
PathTransition​(Duration duration, Shape path);
PathTransition​(Duration duration, Shape path, Node node);

If you want your node to change its direction based on its direction of travel, don’t forget to set the Orientation property to ORTHOGONAL_TO_TANGENT

Timeline

Timelines are the most complex animations in JavaFX, with several classes like the ClipInterpolator and TimelineClipCore that it delegates to to get the job done. But with that complexity is an animation framework that packs a punch.

The JavaFX Timeline object is an Animation designed to update multiple properties over a series of key frames, using multiple interpolation types across an animation. Not all properties must be defined in each key frame, and interpolation is based on the interpolation defined at the end of an interval.

Timelines can be created without any parameters, as well as by specifying keyframes during construction.

Timeline();
Timeline​(double targetFramerate);
Timeline​(double targetFramerate, KeyFrame... keyFrames);
Timeline​(KeyFrame... keyFrames);

You can also change the framerate of the animation be setting the targetFramerate property. You can’t make an animation run more quickly than the highest framerate of the JavaFX animation pulse. However, you can make it fire more slowly.

Key frames are the backbone of Timeline animations. In the next two sections, I’ll cover how to create and modify key frames and key values.

What is a Key Frame?

A key frame is a snapshot in time that captures the states of multiple properties, allowing an animation to move between them. In JavaFX, key frames also manage the interpolation of the time period between the previous key frame and the present one.

A simple animation with two key frames

Here’s an example of an animation with two key frames. It’s easy to define a key frame – we just pass in the time at which it occurs (in the form of a Duration object) and the properties and values it should keep track of.

We’ll add these key frames into the animation by creating the Timeline and passing in each KeyFrame object in a row. I’ll go into more detail about key frames in a minute but they’re essentially an object that holds a reference to a property and a value you want that property to equal.

Rectangle myNode = new Rectangle(100, 100, 100, 100);
myNode.setFill(Color.web("#375fcb"));
pane.getChildren().add(myNode);
myNode.setArcHeight(25);
myNode.setArcWidth(25);
Timeline timeline = new Timeline(
        new KeyFrame(
                Duration.ZERO,
                new KeyValue(
                        myNode.widthProperty(),
                        50d),
                new KeyValue(
                        myNode.heightProperty(),
                        150d
                )
        ),
        new KeyFrame(
                Duration.seconds(1.5),
                new KeyValue(
                        myNode.widthProperty(),
                        150d
                ),
                new KeyValue(
                        myNode.heightProperty(),
                        50d
                )
        )
);
timeline.setAutoReverse(true);
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();

The output of this simple code is a phenomenal tour-de-force in Oscar-winning animation….

Okay, maybe it’s not all the way to the Academy Awards.. Alright, onto key values.

How to modify a key frame

The Timeline class stores key frames as an ObservableList of KeyFrame objects. You can access this list by invoking getKeyFrames() on your timeline.

It’s actually a TrackableObservableList, which automatically updates the inner workings of the timeline when a change is made, so you can add key frames to this list directly. Internally, the Timeline has efficiencies built in so it won’t manually recompute everything if you add a key frame at either the beginning or the end.

Worth noting: However! When you add a key frame your animation will stop. You won’t be able to start it again by calling play(), so instead you’ll have to restart your animation my calling timeline.playFromStart().

What is a Key Value?

The KeyValue is an object that stores a reference to a WriteableValue alongside the numerical value. Key values are stored in KeyFrame objects, which combine this information with the time at which the WriteableValue should equal this number.

The JavaFX animation framework then updates the WriteableValue object over the course of an animation to smoothly move between these values.

Key values can also hold a reference to an Interpolator object, which defines how the value should be interpolated between the previous key frame and this one. This can either be added during construction, or by invoking the setter method setInterpolator() later.

KeyValue​(WritableValue<T> target, T endValue)
KeyValue​(WritableValue<T> target, T endValue, Interpolator interpolator)

The final part of JavaFX’s animation package is the AnimationTimer object.

AnimationTimer

Unlike the other animation classes, there are no default implementations inside the AnimationTimer to update values or nodes inside a Scene. What it does give you access to is the value of the timestamp associated with every animation frame.

The AnimationTimer is an object that listens to the underlying Animation Pulse of the JavaFX animation thread. Once per frame, it calls executable code, defined by the developer, with access to the timestamp of that frame.

This has several uses:

  • As all animations in JavaFX are given the same timestamp this can be really useful for reporting the timestamp of linked events on separate animations.
  • Access to the timestamp means you can calculate the duration of the previous frame. This is essential for creating game loops, or other animations where smoothness is essential.

The AnimationTimer is an abstract class with one abstract method. So, to create an AnimationTimer, we have to override the abstract method. That’s the method that will get called every frame, so any executable code you want to rungoes here.

AnimationTimer timer = new AnimationTimer() {
    @Override
    public void handle(long now) {
        pollUserInput();
        updatePlayerPositions();
        updateCanvas();
    }
};
timer.start();

Warning! You can start the animation timer easily enough by invoking start(), however the stop() method is a little misleading. If you call stop(), the animation timer will stop listening for the pulse, and therefore stop executing your code. However, the timestamps don’t stop!

So, when you start your timer again, if you’re using the timestamps to calculate anything, it’ll be like your animation never stopped!

With a little modification, you can extend the AnimationTimer to add in some proper pausing, stopping and restarting functionality. If you’re interested take a look at my article here, which runs you through how alongside the modified AnimationTimer code.

Conclusions

There are three types of objects in the JavaFX animation portfolio: the Transition classes, Timeline objects and animation timers. Each of these is designed to handle specific use cases, which help developers create beautiful animations.

Transition classes are specifically designed to animate nodes within a scene graph. They specifically alter the appearance and transforms of the nodes. This can be limiting, but generally provides a handful of really useful classes for creating simple animations.

Timelines – the most complex JavaFX animation class, is capable of animating a much broader range of objects. I’ve used them to create complex animations of nodes, but you can also use them to animate any WriteableValue – essentially any JavaFX property.

Finally, the AnimationTimer class is the simplest, but in some ways the most versatile. By giving developers access to the value of the timestamp for each frame, we can create beautiful, smoothed animations and even game loops.