Animation/Transition 的变化率

changing rate of Animation/Transition

我正在尝试制作一些基本的动画,但在最简单的事情上却失败了:

Rectangle rect = new Rectangle(100.0, 10.0);
mainPane.getChildren().add(rect); //so the rectangle is on screen
Animation anim = new Timeline(new KeyFrame(Duration.seconds(30.0),
        new KeyValue(rect.widthProperty(), 0.0, Interpolator.LINEAR)));
rect.setOnMouseClicked(e -> {
    if (anim.getStatus() == Status.RUNNING) {
        anim.pause();
    } else {
        anim.setRate(Math.random() * 5.0);
        anim.play();
        System.out.println(anim.getRate());
    }
});

我遇到的问题是,当我多次点击矩形时,大小会随机跳动,而不是改变它下降的速度。因此,例如,我让它 运行 以 ~2.5 的速度达到大约 50% 的大小,然后停止它。当我再次启动它时,它会跳到一个完全不同的大小,较小的速度较低,较大的速度较高,例如〜1.0速度为〜20%或〜4.5速度为〜80%。

一开始我以为动画是按照新的速度预先计算好的,所以就跳到了应该在的位置,如果之前已经播放的时间从头开始用新的速度播放的话停顿,但速度越慢,停顿越大,这在当时没有意义。

如何更改动画的 speed/rate 而不让它跳来跳去?

我认为您的诊断是正确的:当前值是在给定当前时间和当前速率的情况下内插得出的。如果您在不更改当前时间的情况下降低速率,那么您将在动画中更早。由于动画正在缩小,因此具有使矩形变大的效果。

最简单的方法可能就是每次都开始一个新的动画:

import javafx.animation.Animation;
import javafx.animation.Animation.Status;
import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;

public class VariableRateAnimation extends Application {

    private Animation anim ;

    @Override
    public void start(Stage primaryStage) {
        Pane mainPane = new Pane();
        Rectangle rect = new Rectangle(100.0, 10.0);
        mainPane.getChildren().add(rect); //so the rectangle is on screen
        rect.setOnMouseClicked(e -> {

            if (anim != null && anim.getStatus() == Status.RUNNING) {
                System.out.println("Paused (" + anim.getTotalDuration().subtract(anim.getCurrentTime())+ " remaining)");
                anim.pause();
            } else {
                Duration duration = Duration.seconds(30.0 * rect.getWidth() / (100 * Math.random() * 5.0));
                System.out.println("Starting: ("+duration+ " to go)");
                double currentWidth = rect.getWidth() ;
                if (anim != null) {
                    anim.stop();
                }
                anim = new Timeline(
                        new KeyFrame(Duration.ZERO, new KeyValue(rect.widthProperty(), currentWidth, Interpolator.LINEAR)),
                        new KeyFrame(duration, new KeyValue(rect.widthProperty(), 0.0, Interpolator.LINEAR)));
                anim.play();
            }
        });

        primaryStage.setScene(new Scene(mainPane, 600, 600));
        primaryStage.show();
    }

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