JavaFX2 – BorderPane which slides in and out on command

septembre 18th, 2014

JavaFX package come with many animation/transition effects. This tutorial will show you how to slides Nodes in and out in a BorderPane with a simple command. Contents of each layout pane is shown and hide, using the pane’s layout children (top, left, right, bottom, and center positions). We achieve this with some simple logic and using the pane properties.

As a reminder, BorderPane lays out children in top, left, right, bottom, and center positions.

Borderpane layouts


Let’s look into an example, how we can hide/show our custom nodes by expanding the VBox size in a transition effect. In brief, it is all about clipping our node for some duration of time.

Here is a screenshot of the example to which the transition effect is implemented. On click of “Top” button, the top pane content is shown, on click of “Left” button, the left pane content is hidden and so on…


JavaFX BorderPane which slides in and out on command


The custom BorderSlide class

import javafx.animation.Animation;
import javafx.animation.Transition;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.util.Duration;

/**
 * Animates a node on and off screen to the top, right, bottom or left side.
 */

public class BorderSlideBar extends VBox {
    private final String CSS = "/" + this.getClass().getSimpleName() + ".css";
    private double expandedSize;
    private Pos flapbarLocation;

    /**
     * Creates a sidebar panel in a BorderPane, containing an horizontal alignment
     * of the given nodes.
     *
     * <pre>
     * <code>
     *  Example:
     *
     *  BorderSlideBar topFlapBar = new BorderSlideBar(
     *                  100, button, Pos.TOP_LEFT, new contentController());
     *  mainBorderPane.setTop(topFlapBar);
     * </code>
     * </pre>
     *
     * @param expandedSize The size of the panel.
     * @param controlButton The button responsible to open/close slide bar.
     * @param location The location of the panel (TOP_LEFT, BOTTOM_LEFT, BASELINE_RIGHT, BASELINE_LEFT).
     * @param nodes Nodes inside the panel.
     */

    public BorderSlideBar(double expandedSize,
            final Button controlButton, Pos location, Node... nodes) {

        getStyleClass().add("sidebar");
        getStylesheets().add(CSS);        
        setExpandedSize(expandedSize);
        setVisible(false);

        // Set location
        if (location == null) {
            flapbarLocation = Pos.TOP_CENTER; // Set default location
        }
        flapbarLocation = location;
       
        initPosition();        

        // Add nodes in the vbox
        getChildren().addAll(nodes);

        controlButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent actionEvent) {
                // Create an animation to hide the panel.
                final Animation hidePanel = new Transition() {
                    {
                        setCycleDuration(Duration.millis(250));
                    }

                    @Override
                    protected void interpolate(double frac) {
                        final double size = getExpandedSize() * (1.0 - frac);
                        translateByPos(size);
                    }
                };

                hidePanel.onFinishedProperty().set(new EventHandler<ActionEvent>() {
                    @Override
                    public void handle(ActionEvent actionEvent) {
                        setVisible(false);
                    }
                });

                // Create an animation to show the panel.
                final Animation showPanel = new Transition() {
                    {
                        setCycleDuration(Duration.millis(250));
                    }

                    @Override
                    protected void interpolate(double frac) {
                        final double size = getExpandedSize() * frac;
                        translateByPos(size);
                    }
                };

                showPanel.onFinishedProperty().set(new EventHandler<ActionEvent>() {
                    @Override
                    public void handle(ActionEvent actionEvent) {
                    }
                });

                if (showPanel.statusProperty().get() == Animation.Status.STOPPED
                        && hidePanel.statusProperty().get() == Animation.Status.STOPPED) {

                    if (isVisible()) {
                        hidePanel.play();

                    } else {
                        setVisible(true);
                        showPanel.play();
                    }
                }
            }
        });
    }

    /**
     * Initialize position orientation.
     */

    private void initPosition() {
        switch (flapbarLocation) {
            case TOP_LEFT:
                setPrefHeight(0);
                setMinHeight(0);
                break;
            case BOTTOM_LEFT:
                setPrefHeight(0);
                setMinHeight(0);
                break;
            case BASELINE_RIGHT:
                setPrefWidth(0);
                setMinWidth(0);
                break;
            case BASELINE_LEFT:
                setPrefWidth(0);
                setMinWidth(0);
                break;
        }
    }

    /**
     * Translate the VBox according to location Pos.
     *
     * @param size
     */

    private void translateByPos(double size) {
        switch (flapbarLocation) {
            case TOP_LEFT:
                setPrefHeight(size);
                setTranslateY(-getExpandedSize() + size);                
                break;
            case BOTTOM_LEFT:
                setPrefHeight(size);
                break;
            case BASELINE_RIGHT:
                setPrefWidth(size);
                break;
            case BASELINE_LEFT:
                setPrefWidth(size);
                break;
        }
    }

    /**
     * @return the expandedSize
     */

    public double getExpandedSize() {
        return expandedSize;
    }

    /**
     * @param expandedSize the expandedSize to set
     */

    public void setExpandedSize(double expandedSize) {
        this.expandedSize = expandedSize;
    }
   
}

The Main class

import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ToolBar;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class Main extends Application {

    private static final String STYLESHEET_PATH = "/styles.css";

    @Override
    public void start(Stage stage) {
        Scene scene = new Scene(new Group());
        scene.getStylesheets().add(STYLESHEET_PATH);
        stage.setTitle("Table View Favorite Sample");
        stage.setWidth(600);
        stage.setHeight(431);

        AnchorPane anchorPane = new AnchorPane();
        anchorPane.setPrefHeight(431);
        anchorPane.setPrefWidth(600);

        BorderPane borderPane = new BorderPane();
        borderPane.setPrefHeight(400.0);
        borderPane.setPrefWidth(600.0);
        AnchorPane.setBottomAnchor(borderPane, 0.0);
        AnchorPane.setLeftAnchor(borderPane, 0.0);
        AnchorPane.setRightAnchor(borderPane, 0.0);
        AnchorPane.setTopAnchor(borderPane, 31.0);

        ToolBar toolbar = new ToolBar();
        toolbar.setPrefWidth(600.0);
        AnchorPane.setTopAnchor(toolbar, 0.0);
        AnchorPane.setLeftAnchor(toolbar, 0.0);
        AnchorPane.setRightAnchor(toolbar, 0.0);

        Button buttonTop = new Button("Top");
        Label labelTop = new Label("Top");
       
        Button buttonLeft = new Button("Left");
        Label labelLeft = new Label("Left");
       
        Button buttonBottom = new Button("Bottom");
        Label labelBottom = new Label("Bottom");
       
        Button buttonRight = new Button("Right");
        Label labelRight = new Label("Right");

        /**
         * Instanciate a BorderSlideBar for each childs layouts
         */

        BorderSlideBar topFlapBar = new BorderSlideBar(100, buttonTop, Pos.TOP_LEFT, labelTop);
        borderPane.setTop(topFlapBar);

        BorderSlideBar leftFlapBar = new BorderSlideBar(100, buttonLeft, Pos.BASELINE_LEFT, labelLeft);
        borderPane.setLeft(leftFlapBar);

        BorderSlideBar bottomFlapBar = new BorderSlideBar(100, buttonBottom, Pos.BOTTOM_LEFT, labelBottom);
        borderPane.setBottom(bottomFlapBar);
       
        BorderSlideBar rightFlapBar = new BorderSlideBar(100, buttonRight, Pos.BASELINE_RIGHT, labelRight);
        borderPane.setRight(rightFlapBar);
       
        toolbar.getItems().addAll(buttonTop, buttonLeft, buttonBottom, buttonRight);

        anchorPane.getChildren().addAll(borderPane, toolbar);

        ((Group) scene.getRoot()).getChildren().addAll(anchorPane);

        stage.setScene(scene);
        stage.show();
    }

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

The source code of this sample is available on GitHub.

Happy Coding!!