首页 > 解决方案 > SequentialTransition 内 javafx 中的反向转换

问题描述

给定一个我想反向播放的过渡 t,我使用代码

t.jumpTo(t.getTotalDuration());
t.setRate(-1);

这意味着我跳到过渡的末尾并向后播放。我的问题是,如果我将此转换作为顺序或并行转换的一部分播放,那么它将速率更改为其绝对值,因此它会向前播放。有没有办法“真正”反转转换,即获得一个新的转换,但速率 = 1,所以它在顺序和并行转换中仍然是反向的?

标签: javajavafxreverse

解决方案


对于过渡,这很简单:只需使用Interpolator返回值的a 1-fraction

public class ReverseInterpolator extends Interpolator {

    private final Interpolator reverse;

    public ReverseInterpolator(Interpolator reverse) {
        if (reverse == null) {
            throw new IllegalArgumentException();
        }
        this.reverse = reverse;
    }

    @Override
    protected double curve(double t) {
        return reverse.interpolate(0d, 1d, 1 - t);
    }


    public static Interpolator reverse(Interpolator interpolator) {
        return (interpolator instanceof ReverseInterpolator)
                ? ((ReverseInterpolator) interpolator).reverse
                : new ReverseInterpolator(interpolator);
    }
}
@Override
public void start(Stage primaryStage) throws Exception {
    Rectangle rect1 = new Rectangle(0, 0, 100, 100);
    rect1.setFill(Color.RED);

    Rectangle rect2 = new Rectangle(0, 200, 100, 100);
    rect2.setFill(Color.BLUE);

    Pane root = new Pane(rect1, rect2);

    TranslateTransition transition1 = new TranslateTransition(Duration.seconds(2), rect1);
    transition1.setFromX(0);
    transition1.setToX(400);

    TranslateTransition transition2 = new TranslateTransition(Duration.seconds(2), rect2);
    transition2.setFromX(0);
    transition2.setToX(400);

    ParallelTransition transition = new ParallelTransition(transition1, transition2);
    transition.setOnFinished(evt -> {
        transition2.setInterpolator(ReverseInterpolator.reverse(transition2.getInterpolator()));
        transition.play();
    });
    transition.play();

    primaryStage.setScene(new Scene(root, 500, 500));
    primaryStage.show();
}

对于general Animations,这有点棘手。您可以编写一个Transition在每一帧上设置动画时间的代码:

public class AnimationTransition extends Transition {
    private final Animation animation;

    public AnimationTransition(Animation animation) {
        this.animation = animation;
        setInterpolator(Interpolator.LINEAR);
        setCycleDuration(animation.getCycleDuration());
        setCycleCount(animation.getCycleCount());
        statusProperty().addListener((o, oldValue, newValue) -> {
            switch(newValue) {
                case PAUSED:
                    animation.pause();
                    break;
                case STOPPED:
                    animation.stop();
            }
        });

        // don't actually procede except for playfrom calls
        animation.setRate(0);
    }

    @Override
    protected void interpolate(double frac) {
        animation.playFrom(animation.getCycleDuration().multiply(frac));
    }

}
@Override
public void start(Stage primaryStage) throws Exception {
    Rectangle rect1 = new Rectangle(0, 0, 100, 100);
    rect1.setFill(Color.RED);

    Rectangle rect2 = new Rectangle(0, 200, 100, 100);
    rect2.setFill(Color.BLUE);

    Pane root = new Pane(rect1, rect2);

    TranslateTransition transition1 = new TranslateTransition(Duration.seconds(2), rect1);
    transition1.setFromX(0);
    transition1.setToX(400);


    Timeline timeline = new Timeline(
            new KeyFrame(Duration.ZERO, new KeyValue(rect2.translateXProperty(), 0d)),
            new KeyFrame(Duration.seconds(2), new KeyValue(rect2.translateXProperty(), 400d))
    );
    AnimationTransition transition2 = new AnimationTransition(timeline);

    ParallelTransition transition = new ParallelTransition(transition1, transition2);
    transition.setOnFinished(evt -> {
        transition2.setInterpolator(ReverseInterpolator.reverse(transition2.getInterpolator()));
        transition.play();
    });
    transition.play();

    primaryStage.setScene(new Scene(root, 500, 500));
    primaryStage.show();
}

推荐阅读