在 FXML 中指定关键帧动画

问题描述 投票:0回答:1

如果可以在 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();
    }
}
java javafx fxml
1个回答
0
投票

根据一些实验,执行以下操作是有效的:

<KeyValue target="$someNode.translateXProperty" endValue="..."/>

为什么会这样?没有把握。我无法在“FXML 简介”文档中找到任何解释此行为的内容。但显然使用 xxxProperty 可以为您提供与

xxx
相关的实际 property,而不仅仅是属性的
value

示例

Main.java

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(); } }

控制器.java

package com.example; import javafx.animation.Timeline; import javafx.fxml.FXML; public class Controller { @FXML private Timeline timeline; public void playAnimation() { timeline.play(); } }

Main.fxml

<?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>

© www.soinside.com 2019 - 2024. All rights reserved.