JavaFX: how to create a slide in an animation effect for a panel (inside a transparent scene)

I would like some recommendations on how to implement the transition on the slide for the panel when the user clicks the button, just like Material Design does this for sliding menus.

This is a video link that illustrates my need.

I tried ScaleTransition, TranslateTransition, but they did not do the trick.

The way I'm trying to implement it is inefficient.

// swipeMenuPane is builded in SceneBuilder and it is hidden, // opacity = 0.0 and setX() = -getPrefWidth(); @FXML AnchorPane swipeMenuPane; @FXML Button menuButton; menuButton.setOnMouseClicked(e-> { swipeMenuPane.setOpacity(1.0); swipeTransition.play() }); TranslateTransition swipeTransition = new TranslateTransition(); swipeTransition.setNode(swipeMenuPane); swipeTransition.setDuration(Duration.millis(500)); swipeTransition.setToX(swipeMenuPane.getPrefWidth()); 

--- UPDATE ---

Here is an example of a Gluon application downloaded from here . This is a gradle project, and I modified it to display a button instead of the default label.

I want to compress AnchorPane when the user clicks a button.

What am I missing?

 package com.helloworld; import com.gluonhq.charm.glisten.animation.ShrinkExpandAnimation; import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.layout.AnchorPane; import javafx.scene.layout.StackPane; import javafx.stage.Stage; public class HelloWorld extends Application { ShrinkExpandAnimation anim; @Override public void start(Stage stage) { Button btn = new Button("Click Me!"); btn.setOnMouseClicked(e-> { System.out.println("swiping..."); anim.play(); }); AnchorPane pane = new AnchorPane(); pane.setStyle("-fx-background-color: coral"); pane.getChildren().add(btn); // false to shrink or true to expand anim = new ShrinkExpandAnimation(pane, false); Scene scene = new Scene(new StackPane(pane), 640, 480); stage.setScene(scene); stage.show(); } } 

--- UPDATE 2 ---

I managed to implement something similar to what I want using my own JavaFX API and external libraries.

Although, I ran into some problems.

  • Abbreviation AnchorPane does not abbreviate / move ANY of its children, as they remain in their layout positions.
  • Abbreviation for any panel other than AnchorPane. REDUCING / moving their child nodes except ImageView nodes.

The following two images illustrate the first issue I came across.

This is AnchorPane (with coral color across the entire width, expanded) inside AnchorPane (root panel with gray color).

extended

And this happens when you press the "Menu" button to compress / hide it. As you can see, the panel with a coral shade is compressed / hidden, but not its nodes (Label, ImageView)

collapsed

I am posting all the code to reproduce the problem myself:

 public class SwipeMenuDemo extends Application { AnchorPane swapPane; Button btnMenu; boolean isExpanded = true; @Override public void start(Stage stage) { Label swapPaneLabel = new Label("Expandable Pane"); swapPaneLabel.setMinWidth(0); ImageView swapPaneImage = new ImageView("http://vignette1.wikia.nocookie.net/jfx/images/5/5a/JavaFXIsland600x300.png"); swapPaneImage.setLayoutY(100); Label rootPaneLabel = new Label("Root Pane"); rootPaneLabel.setStyle("-fx-font-size: 60;"); rootPaneLabel.setLayoutX(180); rootPaneLabel.setLayoutY(180); swapPane = new AnchorPane(); swapPane.setPrefSize(640, 440); swapPane.setMinWidth(0); swapPane.setLayoutY(40); swapPane.setStyle("-fx-background-color: coral; -fx-font-size: 52;"); swapPane.getChildren().addAll(swapPaneImage, swapPaneLabel); btnMenu = new Button("Menu"); btnMenu.setLayoutX(5); btnMenu.setLayoutY(5); btnMenu.setOnMouseClicked(e -> { if (isExpanded) hideSwapPane().play(); else showSwapPane().play(); }); Button btnClose = new Button("Close"); btnClose.setLayoutX(590); btnClose.setLayoutY(5); btnClose.setOnMouseClicked(e -> Platform.exit()); AnchorPane rootPane = new AnchorPane(); rootPane.setStyle("-fx-background-color: grey;"); rootPane.getChildren().addAll(btnMenu, btnClose, rootPaneLabel, swapPane); Scene scene = new Scene(rootPane, 640, 480); stage.setScene(scene); stage.initStyle(StageStyle.UNDECORATED); stage.show(); } private Animation hideSwapPane() { btnMenu.setMouseTransparent(true); Animation collapsePanel = new Transition() { { setCycleDuration(Duration.millis(2500)); } @Override protected void interpolate(double fraction) { swapPane.setPrefWidth(640 * (1.0 - fraction)); } }; collapsePanel.setOnFinished(e-> { isExpanded = false; btnMenu.setMouseTransparent(false); }); return collapsePanel; } private Animation showSwapPane() { btnMenu.setMouseTransparent(true); final Animation expandPanel = new Transition() { { setCycleDuration(Duration.millis(2500)); } @Override protected void interpolate(double fraction) { swapPane.setPrefWidth(640 * fraction); } }; expandPanel.setOnFinished(e-> { isExpanded = true; btnMenu.setMouseTransparent(false); }); return expandPanel; } } 

--- UPDATE 3 ---

I changed the Felipe Guizar Diaz code to provide me according to my needs, since I want a shadow effect on my transparent scene window.

When I press the menu button to display the left panel, it appears in front of the shadow. Although in SceneBuilder I placed a StackPane with dropshadow effect in front of all nodes.

This is an β€œartifact” when I click to show the menu and start playing the open transition ...

How can i fix this?

shadow artifact

+9
source share
2 answers

I am the author of an example video. I will repeat the answer that I made in the comments to the video: β€œyou should think of it as a navigation box in android, the navigation box in JavaFX will be AnchorPane with 2 children, first a StackPane , which is equivalent to FrameLayout working as the main content, where transitions depending on the selected item in the menu on the left, and eventually ListView as our menu on the left with negative translateX equal to the width of the ListView . Then, when the user clicks the button, you should play an animation that saves the value of translateX to 0 " You should not use prefWidth() in the method of interpolating two animations (minimize Panel, expand Pane), because children do not resize, field layout is the only constraint that AnchorPane has.

Check out this example I made.

https://github.com/marconideveloper/leftsidemenuexample

 public class FXMLDocumentController implements Initializable { @FXML private Button menu; @FXML private AnchorPane navList; @Override public void initialize(URL url, ResourceBundle rb) { //navList.setItems(FXCollections.observableArrayList("Red","Yellow","Blue")); prepareSlideMenuAnimation(); } private void prepareSlideMenuAnimation() { TranslateTransition openNav=new TranslateTransition(new Duration(350), navList); openNav.setToX(0); TranslateTransition closeNav=new TranslateTransition(new Duration(350), navList); menu.setOnAction((ActionEvent evt)->{ if(navList.getTranslateX()!=0){ openNav.play(); }else{ closeNav.setToX(-(navList.getWidth())); closeNav.play(); } }); } } 

Here is fxml:

 <AnchorPane xmlns:fx="http://javafx.com/fxml/1" id="AnchorPane" prefWidth="500" prefHeight="500" fx:controller="leftslidemenusample.FXMLDocumentController"> <children> <ToolBar AnchorPane.topAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" minHeight="56.0" > <Button text="menu" fx:id="menu" /> </ToolBar> <StackPane fx:id="mainContent" style="-fx-background-color:rgba(0,0,0,0.30)" AnchorPane.bottomAnchor="0.0" AnchorPane.topAnchor="56.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" > <children> </children> </StackPane> <AnchorPane fx:id="navList" style="-fx-background-color:white" AnchorPane.topAnchor="56.0" AnchorPane.bottomAnchor="0.0" prefWidth="180.0" translateX="-180" > <children> <Label text="left side menu"/> </children> </AnchorPane> </children> </AnchorPane> 
+17
source

Finally, I will do everything.

Key features are:

  • Set the shadow effect to the root panel using a custom panel that casts a shadow outside its layout and crop its contents inside, so it has transparent content.
  • The root panel may be something else than AnchorPane.
  • Lock the area containing the main content within its borders.

The following is a snippet of source code that controls these effects:

 @Override public void initialize(URL url, ResourceBundle rb) { ... Rectangle clip = new Rectangle(rootPaneWidth, rootPaneHeight); rootPane.setClip(clip); rootPane.getChildren().add(setupShadowPane()); } private Pane setupShadowPane() { Pane shadowPane = new Pane(); shadowPane.setStyle( "-fx-background-color: white;" + "-fx-effect: dropshadow(gaussian, black, " + shadowSize + ", 0, 0, 0);" + "-fx-background-insets: " + shadowSize + ";" ); Rectangle innerBounds = new Rectangle(); Rectangle outerBounds = new Rectangle(); shadowPane.layoutBoundsProperty().addListener((observable, oldBounds, newBounds) -> { innerBounds.relocate(newBounds.getMinX() + shadowSize, newBounds.getMinY() + shadowSize); innerBounds.setWidth(newBounds.getWidth() - shadowSize * 2); innerBounds.setHeight(newBounds.getHeight() - shadowSize * 2); outerBounds.setWidth(newBounds.getWidth()); outerBounds.setHeight(newBounds.getHeight()); Shape clip = Shape.subtract(outerBounds, innerBounds); shadowPane.setClip(clip); }); return shadowPane; } 

Semi Slide Menu Open

half open

Full Screen Slide Menu

completely open

Slide menu closed

closed

+2
source

All Articles