manejo - javafx ventanas secundarias
JavaFX: cómo crear diapositivas en efecto de animación para un panel(dentro de un escenario transparente) (2)
Finalmente, lo hago.
Sus principales características son:
- Establezca el efecto de sombra en el panel raíz mediante un panel personalizado que adormece una sombra fuera de los límites de su diseño y recorta su contenido interno, por lo que tiene un contenido transparente.
- El panel raíz puede ser cualquier cosa aparte de AnchorPane.
- Recorte el panel que mantiene el contenido principal dentro de sus límites.
A continuación se muestra un fragmento del código fuente que controla estos efectos:
@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;
}
Menú de diapositivas semi abierto
Menú de diapositivas completamente abierto
Menú de diapositivas cerrado
Me gustaría algunas pautas sobre cómo implementar una diapositiva en transición para un panel cuando el usuario presiona un botón, al igual que Material Design lo hace para menús deslizantes.
Este es un enlace de video que ilustra mi necesidad.
Intenté ScaleTransition, TranslateTransition, pero no funcionaron.
La forma en que trato de implementarlo no es eficiente.
// 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());
--- ACTUALIZACIÓN ---
Aquí está la aplicación de Gluon de muestra descargada desde aquí . Es un proyecto de gradle y lo modifiqué para mostrar un botón en lugar de la etiqueta predeterminada.
Quiero reducir el AnchorPane cuando el usuario hace clic en el botón.
¿Qué me estoy perdiendo?
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();
}
}
--- ACTUALIZACIÓN 2 ---
Pude implementar algo similar a lo que quiero usando la API nativa de JavaFX y sin bibliotecas externas.
Aunque, me encontré con algunos problemas.
- Reducir un AnchorPane NO reduce / mueve CUALQUIERA de sus nodos secundarios, ya que permanecen en sus posiciones de disposición.
- Reducir cualquier otro panel excepto AnchorPane HACE que se encojan / muevan sus nodos secundarios excepto desde los nodos ImageView.
Las siguientes dos imágenes ilustran el primer problema con el que me encontré.
Este es un AnchorPane (con color coral en todo su ancho, expandido) dentro de un AnchorPane (panel raíz con color gris).
Y esto es lo que sucede cuando haces clic en el botón Menú para reducirlo / esconderlo. Como puede ver, el panel de color coral se encogió / ocultó, pero NO sus nodos (Label, ImageView)
Publiqué todo el código para reproducir el problema usted mismo:
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;
}
}
--- ACTUALIZACIÓN 3 ---
Modifiqué el código que Felipe Guizar Díaz me proporcionó, según mis necesidades, ya que quiero un efecto de sombra en mi ventana transparente.
Cuando hago clic en el botón de menú para mostrar el panel izquierdo, aparece en frente de la sombra. Aunque en SceneBuilder he colocado el StackPane con el efecto sombra frente a todos los nodos.
Este es el "artefacto" cuando presiono para mostrar el menú y comienza a reproducir la transición abierta ...
¿Cómo puedo arreglarlo?
Yo soy el autor del video de ejemplo. Repetiré la respuesta que hice en los comentarios del video: "debes pensar que es un cajón de navegación en Android, el cajón de navegación en JavaFX sería un AnchorPane
con 2 hijos, primero un StackPane
que es equivalente a un FrameLayout
funcionando como nuestro contenido principal, donde las transiciones del panel se realizan en función del elemento elegido del menú del lado izquierdo y, finalmente, un ListView
como nuestro menú del lado izquierdo con un translateX
negativo que es igual al ancho del Listview
. Luego, cuando el usuario presiona un botón, debe reproducir una animación que muestre el valor de translateX
en 0
". No debe usar prefWidth()
en el método de interpolación de las dos animaciones (colapsar Panel, expandir Panel), porque los niños no AnchorPane
tamaño, la disposición de margen es la única restricción que tiene el AnchorPane
.
Mira este ejemplo que hice.
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();
}
});
}
}
Aquí está el 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>