如何在JavaFX中创建连续的TranslateTransition

时间:2017-04-04 10:00:42

标签: java animation javafx delay transitions

我正在使用JavaFX创建一个Java应用程序,它能够将TranslateTransition应用于通用节点并连续调用它。 我从此网址https://www.google.it/search?q=arrow.png&espv=2&source=lnms&tbm=isch&sa=X&ved=0ahUKEwiGheeJvYrTAhWMB5oKHU3-DxgQ_AUIBigB&biw=1600&bih=764#imgrc=rH0TbMkQY2kUaM中检索了一个简单的右箭头: 并用它来创建要翻译的节点。 这是我的AnimatedNode类:

package application.model.utils.addon;

import javafx.animation.TranslateTransition;
import javafx.scene.Node;
import javafx.util.Duration;

public class AnimatedNode {

    private Node node;
    private double positionY;
    private TranslateTransition translateTransition;
    private boolean animated;

    private int reverse = 1;

    public AnimatedNode(Node node, double animationTime) {
        setPositionY(0.0);
        setNode(node);
        setTranslateTransition(animationTime);
    }

    public void play() {
        if(translateTransition != null && !isAnimated()) {

            setAnimated(true);

            new Thread() {
                @Override
                public void run() {
                    while(isAnimated()) {
                        translateTransition.setToY(positionY + 50 * reverse);
                        translateTransition.play();

                        reverse = -reverse;
                        setPositionY(translateTransition.getToY());
                    }
                }
            }.start();
        }
    }

    public void stop() {
        setAnimated(false);
    }

    public Node getNode() {
        return node;
    }

    private void setNode(Node node) {
        this.node = node;
    }

    public TranslateTransition getTranslateTransition() {
        return translateTransition;
    }

    private void setTranslateTransition(double animationTime) {
        translateTransition = new TranslateTransition();

        if(node != null) {
            translateTransition.setDuration(Duration.seconds(animationTime));
            translateTransition.setNode(node);
        }
    }

    public double getPositionY() {
        return positionY;
    }

    private void setPositionY(double positionY) {
        this.positionY = positionY;
    }

    public boolean isAnimated() {
        return animated;
    }

    private void setAnimated(boolean animated) {
        this.animated = animated;
    }
}

这是Application类

package test;

import application.model.utils.addon.AnimatedNode;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;

public class Test extends Application {

    private final String TITLE = "Test application";
    private final double WIDTH = 600;
    private final double HEIGHT = 400;
    private final String ARROW_PATH = "file:resources/png/arrow.png";

    private BorderPane rootPane;

    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle(TITLE);

        rootPane = new BorderPane();
        rootPane.setPrefSize(WIDTH, HEIGHT);

        Image image = new Image(ARROW_PATH);
        ImageView imageView = new ImageView(image);
        imageView.setFitWidth(WIDTH);
        imageView.setFitHeight(HEIGHT);
        imageView.setPreserveRatio(true);
        AnimatedNode animatedNode = new AnimatedNode(imageView, 0.7);

        Pane pane = new Pane();
        pane.getChildren().add(animatedNode.getNode());

        pane.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent arg0) {
                if(arg0.getButton().equals(MouseButton.PRIMARY))
                    animatedNode.play();

                if(arg0.getButton().equals(MouseButton.SECONDARY))
                    animatedNode.stop();
            }
        });

        rootPane.setCenter(pane);
        Scene scene = new Scene(rootPane, WIDTH, HEIGHT);

        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

该节点被添加到通用窗格中;窗格有一个MouseListener。我可以使用鼠标的主按钮启动TranslateTransition,并使用辅助按钮停止它。 我在AnimatedNode的play()方法中使用了一个Thread,但是在转换中我仍然有一个连续的延迟。 这是进行转换的最佳方式吗?我可以改进我的代码吗?

非常感谢您的支持。

1 个答案:

答案 0 :(得分:0)

示例

这是一个简化示例,演示了通过鼠标左键和右键单击开始和停止的连续动画。

import javafx.animation.*;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.image.*;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import javafx.util.Duration;

public class BouncingCat extends Application {    
    private static final double WIDTH = 100;
    private static final double HEIGHT = 100;
    private final String ARROW_PATH =
            "http://icons.iconarchive.com/icons/iconka/meow-2/64/cat-rascal-icon.png";
            // image source: http://www.iconka.com

    @Override
    public void start(Stage stage) {
        Image image = new Image(ARROW_PATH);
        ImageView imageView = new ImageView(image);
        TranslateTransition animation = new TranslateTransition(
                Duration.seconds(0.7), imageView
        );
        animation.setCycleCount(Animation.INDEFINITE);
        animation.setFromY(0);
        animation.setToY(50);
        animation.setAutoReverse(true);

        Pane pane = new Pane(imageView);
        Scene scene = new Scene(pane, WIDTH, HEIGHT);

        scene.setOnMouseClicked(e -> {
            switch (e.getButton()) {
                case PRIMARY:
                    animation.play();
                    break;

                case SECONDARY:
                    animation.pause();
                    break;
            }
        });

        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

建议

转换时不需要线程。 JavaFX将每个pulse自动呈现更新的过渡帧。

如果在您使用的基础工具中已经表示了相同的值,我建议不要跟踪类中的属性。

例如:

我不建议调用你的AnimatedNode类,除非它扩展节点,否则它会让人感到困惑,而是称之为类似AnimationControl。

import javafx.animation.TranslateTransition;
import javafx.scene.Node;
import javafx.util.Duration;

public class AnimationControl {
    private final TranslateTransition translateTransition;

    public AnimationControl(Duration duration, Node node) {
        translateTransition = new TranslateTransition(duration, node);
    }

    public TranslateTransition getTranslateTransition() {
        return translateTransition;
    }
}

您只需要在AnimationControl中封装节点和转换,而不是其他字段,除非您需要在您的问题中不明显且尚未由Node或Transition提供的其他功能。如果你有这个额外的功能,那么你可以增强上面的AnimationControl类来添加它。

公开节点和转换过渡就足够了,好像用户想要管理动画一样,例如启动和停止它,然后用户可以从AnimationControl类中获取它。根据您的使用情况,整个AnimationControl类可能是不必要的,因为您可能不需要它提供的封装,而可能更喜欢直接使用节点和转换(如示例中演示的那样)。