JavaFX:如何为窗格创建幻灯片动画效果(在透明舞台内) [英] JavaFX: how to create slide in animation effect for a pane (inside a transparent stage)
问题描述
我想要一些关于如何在用户按下按钮时为窗格实现幻灯片转换的指南,就像Material Design为滑动菜单做的那样。
这是一段
当您单击菜单按钮缩小/隐藏它时会发生这种情况。如您所见,珊瑚色窗格缩小/隐藏,但不是它的节点(Label,ImageView)
我发布了整个代码以自己重现问题:
公共类SwipeMenuDemo扩展申请{
AnchorPane swapPane;
Button btnMenu;
boolean isExpanded = true;
@Override
public void start(阶段阶段){
标签swapPaneLabel =新标签(可扩展窗格);
swapPaneLabel.setMinWidth(0);
ImageView swapPaneImage = new ImageView(http://vignette1.wikia.nocookie.net/jfx/images/5/5a/JavaFXIsland600x300.png);
swapPaneImage.setLayoutY(100);
标签rootPaneLabel =新标签(根窗格);
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 =新按钮(菜单);
btnMenu.setLayoutX(5);
btnMenu.setLayoutY(5);
btnMenu.setOnMouseClicked(e - > {
if(isExpanded)hideSwapPane()。play();
else showSwapPane()。play();
});
按钮btnClose = new按钮(关闭);
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);
场景场景=新场景(rootPane,640,480);
stage.setScene(场景);
stage.initStyle(StageStyle.UNDECORATED);
stage.show();
}
私人动画hideSwapPane(){
btnMenu.setMouseTransparent(true);
动画collapsePanel = new Transition(){
{
setCycleDuration(Duration.millis(2500));
}
@Override
protected void interpolate(double fraction){
swapPane.setPrefWidth(640 *(1.0 - fraction));
}
};
collapsePanel.setOnFinished(e-> {
isExpanded = false;
bnnMenu.setMouseTransparent(false);
});
返回collapsePanel;
}
私人动画showSwapPane(){
btnMenu.setMouseTransparent(true);
final动画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);
});
返回expandPanel;
}
}
---更新3 ---
根据我的需要,我修改了Felipe Guizar Diaz提供给我的代码,因为我想要一个影子对我的透明舞台窗口的影响。
当我点击菜单按钮显示左侧窗格时,它会显示在阴影前面。即使在SceneBuilder中,我已经在所有节点前面放置了带有阴影效果的StackPane。
当我按下显示菜单并启动时,这是工件打开过渡...
我该如何解决?
我是示例视频的作者。我将重复我在视频评论中所做的回复:
您应该将其视为android中的导航抽屉,JavaFX中的导航抽屉将是 AnchorPane
有2个孩子,第一个 StackPane
相当于 FrameLayout
作为我们的主要内容,其中转换窗格是根据左侧菜单中选择的项目制作的,最终是 ListView
作为我们的左侧菜单,其中 translateX
等于 Listview
宽度。然后当用户按下按钮时,你必须播放一个动画,其值为 translateX
到 0
。
你不应该在两个动画的插值方法中使用 prefWidth()
(折叠面板,展开窗格),因为孩子们没有调整大小,保证金安排是 AnchorPane
唯一的约束条件。
查看我做的这个例子。
https://github.com/marconideveloper/leftsidemenuexample
公共类FXMLDocumentController实现Initializable {
@FXML
私人按钮菜单;
@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();
}
});
}
}
这是fxml:
< AnchorPane xmlns:fx =http://javafx.com/fxml/1id =AnchorPaneprefWidth =500prefHeight = 500fx:controller =leftslidemenusample.FXMLDocumentController>
< children>
< ToolBar AnchorPane.topAnchor =0.0AnchorPane.leftAnchor =0.0AnchorPane.rightAnchor =0.0minHeight =56.0>
< Button text =menufx:id =menu/>
< / ToolBar>
< StackPane fx:id =mainContentstyle = - fx-background-color:rgba(0,0,0,0.30)AnchorPane.bottomAnchor =0.0AnchorPane.topAnchor =56.0AnchorPane .leftAnchor =0.0AnchorPane.rightAnchor =0.0>
< children>
< / children>
< / StackPane>
< AnchorPane fx:id =navListstyle = - fx-background-color:whiteAnchorPane.topAnchor =56.0AnchorPane.bottomAnchor =0.0prefWidth =180.0translateX = - 180 >
< children>
< Label text =左侧菜单/>
< / children>
< / AnchorPane>
< / children>
< / AnchorPane>
I would like some guidelines on how to implement a slide in transition for a pane when user presses a button, just like Material Design does it for sliding menus.
This is a video link that illustrates my need.
I tried ScaleTransition, TranslateTransition, but they didn't do the trick.
The way I'm trying to implement it is not efficient.
// 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 the sample Gluon Application downloaded from here. It's a gradle project and I modified it to display a button instead of the default label.
I want to shrink the AnchorPane when user clicks the 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 native JavaFX API and no external libraries.
Although, I ran into some issues.
- Shrinking an AnchorPane does NOT shrink/move ANY of its children nodes, because they stay in their layout positions.
- Shrinking any other Pane except AnchorPane DOES shrink/move its children nodes except from ImageView nodes.
The next two images illustrate the 1st issue I ran into.
This is an AnchorPane (with coral color at its full width; expanded) inside an AnchorPane (root pane with grey color).
And this is what happens when you click Menu button to shrink/hide it. As you can see the coral-colored pane got shrinked/hidden, but NOT its nodes (Label, ImageView)
I post the whole code to reproduce the issue yourself:
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 modified the code Felipe Guizar Diaz provide me, according to my needs, since I want a dropshadow effect on my transparent stage window.
When I click the menu button to show the left pane it shows up in front of the shadow. Even though in SceneBuilder I've placed the StackPane with the dropshadow effect in front of all nodes.
This is the "artifact" when I press to show the menu and starts playing the open transition...
How can I fix it?
I am the author of the example video. I'll repeat the response that I did in the video comments:
"you should think of it as a navigation drawer in android, the navigation drawer in JavaFX would be an AnchorPane
with 2 children, first a StackPane
that is equivalent to a FrameLayout
working as our main content, where transitions of pane are made depending of the chosen item from the left side menu, and ultimately a ListView
as our left side menu with a negative translateX
that equals to the Listview
width. Then when the user presses a button you must play an animation that sest the value of translateX
to 0
."
You shouldn't use prefWidth()
in the interpolate method of the two animations (collapse Panel, expand Pane), because the children don't resize, the margin arrangement is the only constraint that the AnchorPane
has.
Check out this example that I did.
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 the 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>
这篇关于JavaFX:如何为窗格创建幻灯片动画效果(在透明舞台内)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!