【问题标题】:How to create a continuous TranslateTransition in JavaFX如何在 JavaFX 中创建连续的 TranslateTransition
【发布时间】:2017-04-04 10:00:41
【问题描述】:

我正在使用 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;
    }
}

这是应用程序类

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() 方法中使用了一个线程,但在转换中我仍然有连续的延迟。 这是执行过渡的最佳方式吗?我可以改进我的代码吗?

非常感谢您的支持。

【问题讨论】:

    标签: java animation javafx delay transitions


    【解决方案1】:

    样本

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

    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 中封装节点和过渡,而不是在其他字段中封装,除非您需要在您的问题中不明显且节点或过渡尚未提供的更多功能。如果你有额外的功能,那么你可以增强上面的 AnimationControl 类来添加它。

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

    【讨论】:

    • 非常感谢您的帮助!如您所见,我不知道Transition类的方法,所以我尝试自己实现一个无限循环。你的方法显然是最好的。
    猜你喜欢
    • 2016-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-07
    相关资源
    最近更新 更多