Search code examples
javafxfadeinfadeoutscenestage

How to use JavaFX FadeTransition In and Out


I'm trying to change the scene of my stage with "fade out" and "fade in" transition. I'm really closed to getting it, but not at all.

First time, it doesn't work. Then, sometimes it works fine and others the new scene is shown completely in milliseconds to after keep on with the rest of transition. The only one runs perfectly is FadeOut.

I think i'm doing something wrong, but i don't know what. I've tried with FadeTransition and Timeline, but the result is always the same.

I show you the fragment of code where i'm working:

//CALLED FROM CONTROLLER WHEN I WANT TO CHANGE THE SCENE

private static FadeTransition fadeOut = new FadeTransition();
private static FadeTransition fadeIn = new FadeTransition();

public void setScene(final String resource_fxml, final String title) {
        fadeOut.setOnFinished(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent event) {
                loadScene(resource_fxml, title);
            }
        });
        fadeOut.setNode(lastRoot);
        fadeOut.setDuration(Duration.millis(Config.TRANSITIONS_TIME));
        fadeOut.setFromValue(1.0);
        fadeOut.setToValue(0.0);
        fadeOut.play();
}

private void loadScene(String resource_fxml, String title) {
        double width = SceneManager.lastScene.getWidth();
        double height = SceneManager.lastScene.getHeight();

        Parent newRoot = null;
        try {
            newRoot = FXMLLoader.load(getClass().getResource(resource_fxml));
        } catch (IOException ex) {
            log.error("Resource not found");
        }

//        DoubleProperty opacity = newRoot.opacityProperty();
//        Timeline fadeIn = new Timeline(
//                new KeyFrame(Duration.ZERO, new KeyValue(opacity, 0.0)),
//                new KeyFrame(Duration.millis(Config.TRANSITIONS_TIME), new KeyValue(opacity, 1.0))
//        );
//        fadeIn.play();

        fadeOut.setNode(newRoot);
        fadeOut.setDuration(Duration.millis(Config.TRANSITIONS_TIME));
        fadeOut.setFromValue(0.0);
        fadeOut.setToValue(1.0);
        fadeOut.play();

        lastScene = new Scene(newRoot, width, height);
        mainStage.setTitle(title);
        mainStage.setScene(lastScene);
        mainStage.show();

        lastRoot = newRoot;

    }

EDIT: I show the final code ("loadScene") that works really fine. Thanks for your tips, Steven Van Impe!

private void loadScene(String resource_fxml, String title) {
        double width = SceneManager.lastScene.getWidth();
        double height = SceneManager.lastScene.getHeight();

        Parent newRoot = null;
        try {
            newRoot = XMLLoader.load(getClass().getResource(resource_fxml));
        } catch (IOException ex) {
            log.error("Resource not found");
        }

        fadeIn.setNode(newRoot);
        fadeIn.setDuration(Duration.millis(Config.TRANSITIONS_TIME));
        fadeIn.setFromValue(0.0);
        fadeIn.setToValue(1.0);

        DoubleProperty opacity = newRoot.opacityProperty();
        opacity.set(0);
        lastScene = new Scene(newRoot, width, height);
        mainStage.setTitle(title);
        mainStage.setScene(lastScene);

        fadeIn.play();

        lastRoot = newRoot;
    }

Solution

  • You are using fadeOut again in loadScene. I take it you want to use fadeIn there? Also, you're starting the animation when the newRoot isn't even part of the scenegraph yet. You might want to try setting up the scene first (but starting newRoot off with an opacity of 0) and then starting the animation.

    As a general note, I would also recommend you don't swap Scenes (or even roots of Scenes) when changing screens, but simply swap out Panes in your GUI. This will give you more flexibility for animations as well. You could, for example, fade in the new pane and fade out the old one at the same time, which isn't possible if you use Scenes.