Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Animation: transitions and Timeline

Animation in JavaFX is a smooth change of a node property over time: its opacity, offset or scale. You set the start value, the end value and the duration, and JavaFX computes the values in between on every frame. The classes live in the javafx.animation package; no extra dependency is needed. In the notebook, animation shows the user what has just happened: the table fades in after loading, the message about a new note fades out on its own, and the title field "shakes" when the title is empty.

Transitions

A transition is a ready-made animation of one property of one node:

ClassWhat it changes
FadeTransitionOpacity, opacity: 0 is invisible, 1 is opaque
TranslateTransitionOffset, translateX and translateY
ScaleTransitionScale, scaleX and scaleY
RotateTransitionRotation angle

The duration is a javafx.util.Duration: Duration.millis(600), Duration.seconds(2). Make sure the IDE does not import java.time.Duration instead: it has no millis method. The other classes in this lesson are imported from javafx.animation.

Fading in

All the code in this lesson goes into MainController.java. In the success handler from the background tasks lesson, make the table fade in:

// src/main/java/com/example/notes/MainController.java — at the end of task.setOnSucceeded(...)
FadeTransition fade = new FadeTransition(Duration.millis(600), table);
fade.setFromValue(0);
fade.setToValue(1);
fade.play();

play() starts the animation and returns at once: the program does not wait for it to finish. Run the application: the table of notes appears out of nothing in 0.6 seconds.

A message that fades away

After a note is added, let the status line show "Note added: …" and fade it out two seconds later. We create one transition in initialize() and restart it each time:

// src/main/java/com/example/notes/MainController.java — a new field, the end of initialize() and a new method
private FadeTransition statusFade;
 
// at the end of initialize():
statusFade = new FadeTransition(Duration.seconds(1), statusLabel);
statusFade.setDelay(Duration.seconds(2));
statusFade.setToValue(0);
 
private void showStatus(String text) {
    statusFade.stop();
    statusLabel.setText(text);
    statusLabel.setOpacity(1);
    statusFade.playFromStart();
}

setDelay postpones the start, and without setFromValue the transition starts from the current opacity. stop() and playFromStart() restart the animation when notes are added faster than the message fades. At the end of addNote(), after clearForm(), call showStatus("Note added: " + title).

Shaking a field

Instead of the Alert warning from the dialogs lesson, shake the title field:

// src/main/java/com/example/notes/MainController.java — the start of addNote() and a new method
if (title.isEmpty()) {
    shake(titleField);
    return;
}
 
private void shake(Node node) {
    TranslateTransition shake = new TranslateTransition(Duration.millis(50), node);
    shake.setFromX(0);
    shake.setByX(8);
    shake.setCycleCount(6);
    shake.setAutoReverse(true);
    shake.play();
}

One pass moves the field 8 pixels to the right, setAutoReverse(true) moves it back, and this happens 6 times. The number of cycles is even, so the field stops where it started. Type a space into the title and click "Add": the field jerks from side to side.

Timeline and KeyFrame

When you need several properties or several stages, use a Timeline. It is made of key frames, KeyFrame: a moment in time plus the KeyValue values the properties must reach by that moment. The "Notes: N" counter will pulse on every change of the list:

// src/main/java/com/example/notes/MainController.java — a new method pulse()
private void pulse(Node node) {
    Timeline timeline = new Timeline(
            new KeyFrame(Duration.ZERO,
                    new KeyValue(node.scaleXProperty(), 1),
                    new KeyValue(node.scaleYProperty(), 1)),
            new KeyFrame(Duration.millis(150),
                    new KeyValue(node.scaleXProperty(), 1.3),
                    new KeyValue(node.scaleYProperty(), 1.3)),
            new KeyFrame(Duration.millis(300),
                    new KeyValue(node.scaleXProperty(), 1),
                    new KeyValue(node.scaleYProperty(), 1)));
    timeline.play();
}
// src/main/java/com/example/notes/MainController.java — in initialize(), after the countLabel binding
notes.addListener((ListChangeListener<Note>) change -> pulse(countLabel));

In 0.15 seconds the label grows to 130 %, and in another 0.15 it shrinks back. Add or delete a note and the counter "jumps". A KeyFrame can also have a handler: new KeyFrame(Duration.seconds(1), event -> ...) together with setCycleCount(Animation.INDEFINITE) runs code once a second, which is how clocks and timers are made.

MethodWhat it does
play(), pause(), stop()Start, pause, stop
playFromStart()Start from the beginning
setCycleCount(n)How many times to repeat; Animation.INDEFINITE means forever
setAutoReverse(true)Every second pass runs backwards
setOnFinished(...)Code to run when the animation ends

Common mistake

The line statusLabel.setOpacity(1) is left out of showStatus. The first message appears and fades, and all the following ones stay invisible: after the first animation the opacity is still 0, the new text goes into an invisible label, and the transition takes it from 0 to 0. There is no error in the terminal. An animation changes the node property itself and does not restore it, so reset the value yourself or call setFromValue.

Thanks for reading!

Donate to the site — we work hard for you.