关键帧之间的 JavaFx 动画延迟

JavaFx Animation delay between keyframes

我有一个小代码片段来启动场景之间的过渡动​​画:

static void initClosingAnimation() {
    ObservableList<Node> components = window.getScene().getRoot().getChildrenUnmodifiable();
    time = new Timeline();
    
    for (Node component : components) {
        KeyValue keyvalue = new KeyValue(component.translateXProperty(), window.getWidth(), Interpolator.EASE_OUT);
        KeyFrame keyframe = new KeyFrame(Duration.seconds(0.4), keyvalue);
        time.getKeyFrames().add(keyframe);
    }
    time.play();
}

该代码从一个场景中获取所有现有组件,然后向每个组件添加一个单独的关键帧,以创建从左到右的过渡。然而,通过这种方式,每个组件都在完全相同的时间移动,这不是我对这个功能的想法。

是否有一种干净的方法可以在每个关键帧之间添加一个小的延迟,以便每个组件一个接一个地淡出,或者甚至可以按照我的想法进行?

只是每个组件使用不同的时间点:

void initClosingAnimation() {
    ObservableList<Node> components = window.getScene().getRoot().getChildrenUnmodifiable();
    time = new Timeline();

    Duration startTime = Duration.ZERO ;
    Duration endTime = Duration.seconds(0.4);

    Duration offset = Duration.seconds(0.1);
    
    for (Node component : components) {
        KeyValue startValue = new KeyValue(component.translateXProperty(), component.getTranslateX(), Interpolator.EASE_OUT);
        KeyValue endValue = new KeyValue(component.translateXProperty(), window.getWidth(), Interpolator.EASE_OUT);
        KeyFrame start = new KeyFrame(startTime, startValue);
        KeyFrame end = new KeyFrame(endTime, endValue);
        time.getKeyFrames().add(start);
        time.getKeyFrames().add(end);
        startTime = startTime.add(offset);
        endTime = endTime.add(offset);
    }
    time.play();
}

这是一个完整的例子(对上面的方法签名稍作修改):

import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.collections.ObservableList;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.stage.Window;
import javafx.util.Duration;


public class App extends Application {

    @Override
    public void start(Stage stage) {
        VBox root = new VBox(5);
        root.setAlignment(Pos.CENTER);
        for (int i = 1 ; i <= 10 ; i++) root.getChildren().add(new Label("Item "+i));
        Button close = new Button("Close");
        root.getChildren().add(close);
        close.setOnAction(e -> initClosingAnimation(stage, stage::hide));
        Scene scene = new Scene(root, 400, 600);
        stage.setScene(scene);
    
        stage.setOnCloseRequest(e -> {
            initClosingAnimation(stage, stage::hide);
            e.consume();
        });
    
        stage.show();
    }
    
    private void initClosingAnimation(Window window, Runnable onFinished) {
        ObservableList<Node> components = window.getScene().getRoot().getChildrenUnmodifiable();
        Timeline time = new Timeline();

        Duration startTime = Duration.ZERO ;
        Duration endTime = Duration.seconds(0.4);

        Duration offset = Duration.seconds(0.1);
        
        for (Node component : components) {
            KeyValue startValue = new KeyValue(component.translateXProperty(), component.getTranslateX(), Interpolator.EASE_OUT);
            KeyValue endValue = new KeyValue(component.translateXProperty(), window.getWidth(), Interpolator.EASE_OUT);
            KeyFrame start = new KeyFrame(startTime, startValue);
            KeyFrame end = new KeyFrame(endTime, endValue);
            time.getKeyFrames().add(start);
            time.getKeyFrames().add(end);
            startTime = startTime.add(offset);
            endTime = endTime.add(offset);
        }
        time.setOnFinished(e -> onFinished.run());
        time.play();
    }

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

}