If keyframe animation can be specified in FXML, then a lot of file formats containing animations can be ported to FXML without information loss. I'm aware of the simpler variants like RotateTransition.
The most straightforward approach of declaring the KeyValue target as $text.translateX (or the other variations I could think of gave type-checking runtime errors.
After some fiddling, I managed to come up with code that doesn't give errors, but the target binding also doesn't seem to happen. I've added a line to the controller for that to allow easy testing of what the wanted behavior is. How can I get rid of that line and make it work just with FXML? Shouldn't it also work with $text.translateX?
animated.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.animation.*?>
<?import javafx.beans.property.SimpleDoubleProperty?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.Group?>
<?import javafx.scene.Scene?>
<?import javafx.scene.text.Text?>
<?import javafx.util.Duration?>
<?import java.lang.Double?>
<Scene xmlns:fx="http://javafx.com/fxml" fx:controller="org.example.demo.AnimatedController">
<height>240.0</height>
<width>320.0</width>
<fx:define>
<SimpleDoubleProperty fx:id="count"/>
<Timeline fx:id="timeline">
<keyFrames>
<fx:define>
<Double fx:id="endValue0" fx:value="0.0"/>
<Double fx:id="endValue1" fx:value="100.0"/>
</fx:define>
<KeyFrame fx:id="keyFrame0">
<values>
<KeyValue fx:id="keyValue0" endValue="$endValue0">
<target>
<fx:reference source="count"/>
</target>
</KeyValue>
</values>
<time>
<Duration fx:constant="ZERO"/>
</time>
</KeyFrame>
<KeyFrame fx:id="keyFrame1">
<values>
<KeyValue fx:id="keyValue1" endValue="$endValue1">
<target>
<fx:reference source="count"/>
</target>
</KeyValue>
</values>
<time>
<Duration millis="1000"/>
</time>
</KeyFrame>
</keyFrames>
</Timeline>
</fx:define>
<Group>
<Text fx:id="text" y="60" x="${count.value}">Hello, World!</Text>
<Button onAction="#play">Play</Button>
</Group>
</Scene>
AnimatedController.java
package org.example.demo;
import javafx.animation.Timeline;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.text.Text;
public class AnimatedController {
@FXML
private Text text;
@FXML
private Timeline timeline;
@FXML
private SimpleDoubleProperty count = new SimpleDoubleProperty(0);
public void play(ActionEvent ignoredActionEvent) {
text.xProperty().bind(count); // without this line, text.getX() doesn't get updated
count.addListener((_, oldVal, newVal) -> System.out.printf("%s, %s, %s\n", text.getX(), oldVal, newVal));
timeline.play();
}
}
HelloApplication.java
package org.example.demo;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
public class HelloApplication extends Application {
@Override
public void start(Stage stage) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("animated.fxml"));
Scene scene = fxmlLoader.load();
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
x="${count}"work (or eventranslateX="${count}")?${reference}syntax is an expression binding, the$referencesyntax is variable reference. As pointed out by Slaw, you probably want a binding in your FXML if you want to replace the binding you currently have in code. And probably you want to bind thetranslateXas that is usually what is animated rather thanx(which is usually used for layout)....="${count}fails because then it fails to parse the string representation "DoubleProperty [...]" to a double. If I subclass SimpleDoubleProperty to overridetoString()withreturn this.getValue().toString();, I don't get an error when using..="${count}", but still no animation.