如果可以在 FXML 中指定关键帧动画,那么很多包含动画的文件格式都可以移植到 FXML,而不会丢失信息。我知道更简单的变体,例如
RotateTransition
。
将 KeyValue 目标声明为
$text.translateX
的最直接方法(或我能想到的其他变体会导致类型检查运行时错误。
经过一番摆弄后,我设法想出了不会给出错误的代码,但目标绑定似乎也没有发生。我在控制器中添加了一行,以便轻松测试所需的行为。我怎样才能摆脱这条线并使其仅适用于 FXML?不是也可以和$text.translateX
一起使用吗?
动画.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();
}
}
根据一些实验,执行以下操作是有效的:
<KeyValue target="$someNode.translateXProperty" endValue="..."/>
为什么会这样?没有把握。我无法在“FXML 简介”文档中找到任何解释此行为的内容。但显然使用 xxxProperty
可以为您提供与
xxx
相关的实际 property,而不仅仅是属性的 value。 示例
package com.example;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
public class Main extends Application {
@Override
public void start(javafx.stage.Stage primaryStage) throws Exception {
var loader = new FXMLLoader();
loader.setLocation(Main.class.getResource("/Main.fxml"));
var root = loader.<Parent>load();
var controller = loader.<Controller>getController();
primaryStage.setScene(new Scene(root, 600, 400));
primaryStage.show();
controller.playAnimation();
}
}
package com.example;
import javafx.animation.Timeline;
import javafx.fxml.FXML;
public class Controller {
@FXML private Timeline timeline;
public void playAnimation() {
timeline.play();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.Double?>
<?import javafx.animation.Animation?>
<?import javafx.animation.KeyFrame?>
<?import javafx.animation.KeyValue?>
<?import javafx.animation.Timeline?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.util.Duration?>
<StackPane xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml"
fx:controller="com.example.Controller">
<Label fx:id="label" text="Hello, World!" />
<fx:define>
<Double fx:id="fromValue" fx:value="-100.0" />
<Double fx:id="toValue" fx:value="100.0" />
<Duration fx:id="startTime" fx:constant="ZERO" />
<Duration fx:id="endTime" millis="1000.0" />
<Timeline fx:id="timeline" autoReverse="true">
<cycleCount>
<Animation fx:constant="INDEFINITE" />
</cycleCount>
<keyFrames>
<KeyFrame time="$startTime">
<values>
<KeyValue target="$label.translateXProperty" endValue="$fromValue" />
</values>
</KeyFrame>
<KeyFrame time="$endTime">
<values>
<KeyValue target="$label.translateXProperty" endValue="$toValue" />
</values>
</KeyFrame>
</keyFrames>
</Timeline>
</fx:define>
</StackPane>