Issue
i will try to expose my problem as good as i can.
This is the XML
<VBox fx:id="main" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity"
prefHeight="500.0" prefWidth="800.0" style="-fx-background-color: #DEE2E6;" xmlns="http://javafx.com/javafx/17"
xmlns:fx="http://javafx.com/fxml/1">
<BorderPane prefHeight="408.0" prefWidth="600.0" VBox.vgrow="ALWAYS">
<left>
<AnchorPane fx:id="section_to_hide" prefHeight="200.0" prefWidth="200.0" style="-fx-background-color: red;" BorderPane.alignment="CENTER">
<Label fx:id="hide_btn1" layoutX="14.0" layoutY="54.0" onMouseClicked="#hide" text="Hide me">
<font>
<Font name="Prompt-Black" size="24.0"/>
</font>
</Label>
</AnchorPane>
</left>
<center>
<BorderPane fx:id="main_content" prefHeight="442.0" prefWidth="600.0" BorderPane.alignment="CENTER">
<left>
<VBox fx:id="side_section_mails" prefHeight="500.0" prefWidth="200.0" BorderPane.alignment="CENTER">
<AnchorPane prefHeight="59.0" prefWidth="200.0">
<Label fx:id="hide_btn" layoutX="14.0" layoutY="19.0" onMouseClicked="#hide" text="< Hide it">
<font>
<Font name="Prompt-Black" size="24.0"/>
</font>
</Label>
</AnchorPane>
</VBox>
</left>
<center>
<AnchorPane prefHeight="200.0" prefWidth="200.0" style="-fx-background-color: #CED4DA;" BorderPane.alignment="CENTER"/>
</center>
</BorderPane>
</center>
</BorderPane>
</VBox>
Controller:
public class Controller {
@FXML
private Label hide_btn;
@FXML
private AnchorPane section_to_hide;
@FXML
private void hide() {
Animation animation = new Timeline(
new KeyFrame(Duration.millis(300),
new KeyValue(section_to_hide.prefWidthProperty(), 0),
new KeyValue(section_to_hide.minWidthProperty(), 0)
)
);
animation.play();
}
@FXML
public void initialize() { }
}
The problem is: i want the content of the AnchorPane (section_to_hide) to collapse with its parent. Because this is what happens:
https://gyazo.com/41dfc5340a8e4495938cbc43d801fea2
It seems that the label inside the AnchorPane (section_to_hide) does not collapse with the parent. Is there a way to make it work?
Solution
+1 for @Oboe answer. I would like add a bit more to his answer.
If you set managed/visible to false after the animation is finished, you may not see a smooth transition of the label. Means the complete Label is still visible while the pane closes (as in below gif) and gets invisible only after the animation is finished.
On the other hand, if you bind the clip with the bounds of the section that is hiding, you will get an effect of hiding something with a piece of cover (as in below gif) but not like hiding by sliding the section.
If the above behaviour is Ok for you, then no issues :). But if your are looking for a peferct sliding animation (as in below gif), you need to add another change of translating the clip position also.
But for this, you will need to wrap the hiding pane with an extra container. The end implementation will be :
- Outer container width is reduced to 0
- Hiding container is translated in negative direction
- And the clip is translated in positive direction.
Wrap section_to_hide with StackPane in fxml:
<StackPane fx:id="section_to_hide_container" prefHeight="200.0" prefWidth="200.0" alignment="CENTER_LEFT">
<AnchorPane fx:id="section_to_hide" prefHeight="200.0" prefWidth="200.0" style="-fx-background-color: red;" >
<children>
<Label fx:id="hide_btn1" layoutX="14.0" layoutY="54.0" onMouseClicked="#hide"
text="Hide me">
<font>
<Font name="Prompt-Black" size="24.0"/>
</font>
</Label>
</children>
</AnchorPane>
</StackPane>
And you controller code will change as below:
@FXML
private StackPane section_to_hide_container;
@FXML
private void hide() {
double width = section_to_hide_container.getWidth();
// Create a clip and apply on the pane to hide
Rectangle clip = new Rectangle();
clip.setWidth(width);
clip.heightProperty().bind(section_to_hide.heightProperty());
section_to_hide.setClip(clip);
Animation animation = new Timeline(
new KeyFrame(Duration.millis(300),
new KeyValue(section_to_hide_container.prefWidthProperty(), 0),
new KeyValue(section_to_hide.translateXProperty(), -width),
new KeyValue(clip.translateXProperty(), width)
)
);
animation.setOnFinished(e -> {
// Removing the clips
clip.heightProperty().unbind();
section_to_hide.setClip(null);
//Hiding the panes at the end
section_to_hide_container.setVisible(false);
section_to_hide.setVisible(false);
});
animation.play();
}
@FXML
public void initialize() {
// Binding min/max to pref, to not allow the panes width change.
section_to_hide_container.minWidthProperty().bind(section_to_hide_container.prefWidthProperty());
section_to_hide_container.maxWidthProperty().bind(section_to_hide_container.prefWidthProperty());
section_to_hide.minWidthProperty().bind(section_to_hide.prefWidthProperty());
section_to_hide.maxWidthProperty().bind(section_to_hide.prefWidthProperty());
}
I wrote a detailed blog about this particular feature. Please do check to get more inputs on this. Also please note that this blog was written almost 10 years back with my knowledge at that time. So some code and wordings may not be relevant now :)
Answered By - Sai Dandem
Answer Checked By - Mildred Charles (JavaFixing Admin)