JavaFX:如何为窗格创建幻灯片动画效果(在透明舞台内) [英] JavaFX: how to create slide in animation effect for a pane (inside a transparent stage)

查看:317
本文介绍了JavaFX:如何为窗格创建幻灯片动画效果(在透明舞台内)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想要一些关于如何在用户按下按钮时为窗格实现幻灯片转换的指南,就像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.

  1. Shrinking an AnchorPane does NOT shrink/move ANY of its children nodes, because they stay in their layout positions.
  2. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆