提问人:Bursh 提问时间:11/14/2023 更新时间:11/15/2023 访问量:67
在时间轴中同时播放的 JavaFX 动画
JavaFX animations playing simultaneously in timeline
问:
我是 JavaFX 的新手。我正在尝试制作这个时间线,其中每个关键帧都发生在前一个关键帧完成之后。到目前为止,每个步骤都像我想要的那样一个接一个地发生。但是,一旦我播放动画,rotateBack 关键帧就会开始旋转我的对象。关于如何使 rotateBack 仅在 moveToRight 之后播放的任何提示?另外,我希望 rotateBack 在 moveToTop 播放之前完成其旋转。谢谢。
Pane selectedPane = select_pane.getValue();
double rootWidth = root_pane.getWidth();
double rootHeight = root_pane.getHeight();
double sixthWidth = rootWidth / 6;
KeyValue moveTopLeftX = new KeyValue(selectedPane.layoutXProperty(), 0);
KeyValue moveDownY = new KeyValue(selectedPane.layoutYProperty(), root_pane.getHeight() - selectedPane.getHeight());
KeyValue moveRightX = new KeyValue(selectedPane.layoutXProperty(), sixthWidth);
KeyValue rotate180 = new KeyValue(selectedPane.rotateProperty(), 180);
KeyValue moveToTopY = new KeyValue(selectedPane.layoutYProperty(), 0);
KeyFrame startFrame = new KeyFrame(Duration.seconds(3), moveTopLeftX, moveToTopY);
KeyFrame moveToRight = new KeyFrame(Duration.seconds(2), moveRightX);
KeyFrame rotateBack = new KeyFrame(Duration.seconds(3), rotate180);
KeyFrame moveToBottom = new KeyFrame(Duration.seconds(6), moveDownY);
KeyFrame moveToTop = new KeyFrame(Duration.seconds(6), moveToTopY);
Timeline timeline = new Timeline(startFrame, moveToBottom, moveToRight, rotateBack, moveToTop);
timeline.play();
到目前为止,我尝试的内容显示在上面的代码中。任何提示非常感谢。
答:
要仅在关键帧完成后播放关键帧,您可以创建不同的时间轴,并在 timeline.setOnFinished() 函数中播放下一个关键帧。
对于您的示例,它看起来像这样:
Pane selectedPane = select_pane.getValue();
double rootWidth = root_pane.getWidth();
double rootHeight = root_pane.getHeight();
double sixthWidth = rootWidth / 6;
KeyValue moveTopLeftX = new KeyValue(selectedPane.layoutXProperty(), 0);
KeyValue moveDownY = new KeyValue(selectedPane.layoutYProperty(), root_pane.getHeight() - selectedPane.getHeight());
KeyValue moveRightX = new KeyValue(selectedPane.layoutXProperty(), sixthWidth);
KeyValue rotate180 = new KeyValue(selectedPane.rotateProperty(), 180);
KeyValue moveToTopY = new KeyValue(selectedPane.layoutYProperty(), 0);
KeyFrame startFrame = new KeyFrame(Duration.seconds(3), moveTopLeftX, moveToTopY);
KeyFrame moveToRight = new KeyFrame(Duration.seconds(2), moveRightX);
KeyFrame rotateBack = new KeyFrame(Duration.seconds(3), rotate180);
KeyFrame moveToBottom = new KeyFrame(Duration.seconds(6), moveDownY);
KeyFrame moveToTop = new KeyFrame(Duration.seconds(6), moveToTopY);
Timeline timelineStart = new Timeline(startFrame, moveToBottom, moveToRight);
Timeline timelineRotateBack = new Timeline(rotateBack);
Timeline timelineMoveToTop = new Timeline(moveToTop);
timelineStart.setOnFinished(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
timelineRotateBack.play();
}
});
timelineRotateBack.setOnFinished(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
timelineMoveToTop.play();
}
});
timelineStart.play();
在这里,它将首先播放所有这些关键帧(startFrame、moveToBottom、moveToRight),当所有动画完成后,它将播放 rotateBack 关键帧,当这个动画完成时,它将播放 moveToTop
过渡非常适合这个问题
本文提供了一个基于 SequentialTransition
的示例,而不是 .您可以改用 a,如其他评论或答案中所述。但是,对于您描述的功能,使用过渡似乎更合适。Timeline
Timeline
该示例对各种类型的事务进行排序,并执行所需的动画。TranslateTransition
RotateTransition
如果您希望并行执行序列的某些部分,则可以对这些部分使用 a(如果需要,可以合并并行和顺序转换)。ParallelTransition
使用动画的平移属性
执行动画时应使用 translateX/Y/Z 属性,而不是 layoutX/Y 属性。虽然您可以对布局更改进行动画处理,但这是一个高级主题,不建议刚接触 JavaFX 的人使用。此处提供的示例基于翻译属性,而不是布局属性。
选择合适的插值器
关键帧的默认插值器为 LINEAR,
过渡的默认插值器为 EASE_BOTH
。通过在关键帧或转场上设置插值器,选择适合您应用的插值器。对于这个例子,我觉得过渡的默认插值是最适合的,从而产生了更平滑的动画感觉。EASE_BOTH
示例代码
import javafx.animation.*;
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
import java.io.IOException;
public class TransitionApp extends Application {
private static final Color INDIA_INK = Color.web("#3d3f4a");
private static final double W = 400, H = 400;
private static final double BOX_W = 20, BOX_H = 20;
private static final double BOX_TOP_SIDE_INDICATOR_H = 3;
private static final double MOVE_STEP = 50;
private static final Duration TIME_STEP = Duration.seconds(3);
public void start(Stage stage) throws IOException {
Group box = createBox(BOX_W, BOX_H, BOX_TOP_SIDE_INDICATOR_H);
box.setTranslateX(W / 2 - BOX_W / 2);
box.setTranslateY(H / 2 - BOX_H / 2);
Pane root = new Pane(box);
root.setBackground(Background.fill(INDIA_INK));
root.setPrefSize(W, H);
stage.setResizable(false);
stage.setScene(new Scene(root));
stage.show();
SequentialTransition transition = createTransition(box);
transition.play();
}
private SequentialTransition createTransition(Group box) {
TranslateTransition moveToTopLeft = new TranslateTransition(TIME_STEP);
moveToTopLeft.setToX(0);
moveToTopLeft.setToY(0);
TranslateTransition moveToBottom = new TranslateTransition(TIME_STEP.multiply(2));
moveToBottom.setToY(H - BOX_H);
TranslateTransition moveRight = new TranslateTransition(TIME_STEP);
moveRight.setToX(MOVE_STEP);
RotateTransition rotate180 = new RotateTransition(TIME_STEP);
rotate180.setByAngle(180);
TranslateTransition moveToTop = new TranslateTransition(TIME_STEP.multiply(2));
moveToTop.setToY(0);
SequentialTransition sequentialTransition = new SequentialTransition(
box,
moveToTopLeft, moveToBottom, moveRight, rotate180, moveToTop
);
sequentialTransition.setAutoReverse(true);
sequentialTransition.setCycleCount(Transition.INDEFINITE);
return sequentialTransition;
}
private static Group createBox(double w, double h, double topSideIndicatorH) {
Rectangle rectangle = new Rectangle(
w, h, Color.GREEN
);
Rectangle topLine = new Rectangle(
w, topSideIndicatorH, Color.RED
);
return new Group(
rectangle, topLine
);
}
public static void main(String[] args) {
launch(args);
}
}
评论
KeyFrame
new KeyFrame(Duration.seconds(2), new KeyValue(selectedPane.rotateProperty(), selectedPane.getRotate()))