user3164187
user3164187

Reputation: 1432

JavaFX : StackPane Sequential Transition

I am trying to switch between 3 different AnchorPane (on click of a Button) with a FadeTransition and below is my code,

public class TestSlide extends Application {
    private ObjectBinding<Node> frontNode;

    @Override
    public void start(Stage primaryStage) {

        StackPane root = new StackPane();
        AnchorPane pane1 = new AnchorPane(new Button("1"));
        AnchorPane pane2 = new AnchorPane(new Button("2"));
        AnchorPane pane3 = new AnchorPane(new Button("3"));
        root.getChildren().addAll(pane1, pane2, pane3);

        handleAnimation(root);

        BorderPane border= new BorderPane(root);

        HBox bottom = new HBox(10);
        Button front1 = new Button("Pane 1");
        Button front2 = new Button("Pane 2");
        Button front3 = new Button("Pane 3");
        front1.setOnAction((ActionEvent event) -> {
            pane1.toFront();
        });
        front2.setOnAction((ActionEvent event) -> {
            pane2.toFront();
        });
        front3.setOnAction((ActionEvent event) -> {
            pane3.toFront();
        });
        bottom.getChildren().addAll(front1, front2, front3);
        border.setBottom(bottom);

        Scene scene = new Scene(border,400,400);
        primaryStage.setScene(scene);
        primaryStage.show();

    }

    private void handleAnimation(StackPane root) {
        frontNode = Bindings.valueAt(root.getChildren(),
                Bindings.size(root.getChildren()).subtract(1));
        frontNode.addListener((obs, oldNode, newNode) -> {
            SequentialTransition fadeOutIn = new SequentialTransition();
            if (oldNode != null) {
                FadeTransition fadeOut = new FadeTransition(Duration.millis(500), oldNode);
                fadeOut.setToValue(0);
                fadeOutIn.getChildren().add(fadeOut);
            }
            if (newNode != null) {
                FadeTransition fadeIn = new FadeTransition(Duration.millis(500), newNode);
                fadeIn.setFromValue(0);
                fadeIn.setToValue(1);
                fadeOutIn.getChildren().add(fadeIn);
            }
            fadeOutIn.play();
        });
    }

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

The handleAnimation method is referenced from another SO post.

The problem is ,

  1. After launching the application, Click on Pane 1 Button. -> Transition will first show pane2 and then pane1.

  2. Now Click on Pane 3 Button -> Transition will first show pane2 and then pane3.

  3. Now Click on Pane 2 Button -> Transition will show pane2 and the problem mentioned in above 2 points doesn't appear again.

Why the transition shows pane2 before showing the actual pane in points 1 & 2 ? is it due to opacity setting ?

and why after point 3 the problem gets resolved ?

How can i make the transition work to FadeIn and FadeOut the respective Pane without showing the third Pane ?

Upvotes: 3

Views: 408

Answers (1)

fabian
fabian

Reputation: 82491

The issue here is that the initial state of the children of the StackPane is wrong: All nodes have opacity 1. Your desired state when no animation is running has all the nodes but the last one fully transparent (opacity = 0) and the last one fully opaque (opacity = 1). You should be able to fix the issue by initializing the opacities properly:

root.getChildren().addAll(pane1, pane2, pane3);

// set opacity for all but the last child to 0
List<Node> children = root.getChildren();
for (int i = children.size()-2; i >= 0; i--) {
    children.get(i).setOpacity(0);
}

Otherwise the following happens:

Just after pane1.toFront(). Note that (SequentialTransition makes sure that the state for the start of the animation is established.

The topmost node is the last child in the list and ----... is put next to the visible "layer".

Pane 1: opacity = 0
Pane 3: opacity = 1 ------------------------------
Pane 2: opacity = 1

Now after the first half of the SequentialTransition is done, this looks as follows:

Pane 1: opacity = 0
Pane 3: opacity = 0
Pane 2: opacity = 1 ------------------------------

And after the animation is completeled:

Pane 1: opacity = 1 ------------------------------
Pane 3: opacity = 0
Pane 2: opacity = 1

Using pane3.toFront() produces similar results:

Pane 3: opacity = 0
Pane 1: opacity = 1 ------------------------------
Pane 2: opacity = 1
Pane 3: opacity = 0
Pane 1: opacity = 0
Pane 2: opacity = 1 ------------------------------
Pane 3: opacity = 1 ------------------------------
Pane 1: opacity = 0
Pane 2: opacity = 1

Upvotes: 4

Related Questions