【问题标题】:JavaFX: how to create slide in animation effect for a pane (inside a transparent stage)JavaFX:如何为窗格创建幻灯片动画效果(在透明舞台内)
【发布时间】:2015-10-14 14:48:18
【问题描述】:

我想要一些关于如何在用户按下按钮时为窗格实现幻灯片过渡的指南,就像 Material Design 为滑动菜单所做的那样。

这是一个视频link,说明了我的需求。

我尝试了 ScaleTransition、TranslateTransition,但他们没有成功。

我尝试实现它的方式效率不高。

// 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());

--- 更新 ---

这是从here 下载的示例 Gluon 应用程序。这是一个 gradle 项目,我对其进行了修改以显示一个按钮而不是默认标签。

我想在用户单击按钮时缩小 AnchorPane。

我错过了什么?

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();
    }
}

--- 更新 2 ---

我设法使用本机 JavaFX API 实现了类似于我想要的东西,并且没有使用外部库。

虽然,我遇到了一些问题。

  1. 收缩 AnchorPane 不会收缩/移动其任何子节点,因为它们会停留在其布局位置。
  2. 收缩除 AnchorPane 之外的任何其他窗格会收缩/移动其子节点,但 ImageView 节点除外。

接下来的两张图片说明了我遇到的第一个问题。

这是 AnchorPane(灰色根窗格)内的 AnchorPane(全宽珊瑚色;展开)。

当您单击菜单按钮以缩小/隐藏它时会发生这种情况。如您所见,珊瑚色窗格已缩小/隐藏,但不是其节点(标签、ImageView)

我发布了整个代码来自己重现问题:

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;
    }
}

--- 更新 3 ---

我根据我的需要修改了 Felipe Guizar Diaz 提供给我的代码,因为我想要在我的透明舞台窗口上添加阴影效果。

当我单击菜单按钮以显示左窗格时,它会显示在阴影前面。即使在 SceneBuilder 中,我已将具有阴影效果的 StackPane 放置在所有节点的前面。

这是当我按下以显示菜单并开始播放打开的过渡时的“工件”...

我该如何解决?

【问题讨论】:

  • 能否请您添加您已经尝试过的代码?
  • 也许您正在寻找像 HiddenSidesPane 这样的东西?看这里:fxexperience.com/controlsfx/features/#hiddensidespane
  • @NwDx 是的,但在我的情况下,我希望窗格在鼠标事件时显示/滑动。你遇到过这样的事情吗?
  • 嗯,也许您想要类似 material design 的 Android 应用程序?那么Gluon Charm 可能就是你要找的东西。
  • 如果我能自己实现同样的动画效果就好了。我查看了类似的代码,但它们不适合我的情况(我想)。我要滑入的窗格将覆盖整个舞台。这就像打开一个抽屉然后又把它关上。有人可以提供任何指导方针或步骤来考虑采取吗?

标签: javafx


【解决方案1】:

我是示例视频的作者。我将重复我在视频 cmets 中所做的响应: “您应该将其视为 android 中的导航抽屉,JavaFX 中的导航抽屉将是一个带有 2 个孩子的AnchorPane,首先是一个StackPane,它相当于一个FrameLayout,作为我们的主要内容,其中的转换窗格是根据左侧菜单中选择的项目制作的,最后是 ListView 作为我们的左侧菜单,其负数 translateX 等于 Listview 宽度。然后当用户按下按钮时,您必须播放将translateX 的值设置为0 的动画。" 你不应该在两个动画(折叠面板,展开面板)的插值方法中使用prefWidth(),因为孩子不会调整大小,边距排列是AnchorPane的唯一约束。

看看我做的这个例子。

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();
            }
        });
    }
}

这是 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>

【讨论】:

  • 哦!这就是问题所在!移动窗格而不是调整它的大小!非常感谢您的支持。但是,我想知道如何实现手风琴效果?在这种情况下,我想您处理的是调整大小而不是移动它?
  • 我修改了你的代码,让它在我的舞台上有阴影效果,但是有一个神器。你能看看上图吗?
  • 好吧,当你放置一个阴影时会创建一个边距,这是在阴影前面出现导航的原因,你应该把效果放在根锚窗格中并设置一个剪辑,检查 setclip 方法在 javafx 文档中的 Node 类中。
  • 我不太明白你的意思。根锚窗格大小为 500x500px(阴影效果为 10px 阴影宽度),所以我创建了一个 500x500px 的矩形剪辑。但这也会产生阴影。怎么办?
【解决方案2】:

终于搞定了。

它们的主要特点是:

  1. 使用自定义窗格在根窗格上设置阴影效果,该窗格会在其布局边界之外投射阴影并裁剪其内部内容,因此它具有透明内容。
  2. 根窗格可以是 AnchorPane 以外的任何东西。
  3. 将包含主要内容的窗格剪切到其内部边界。

下面是控制这些效果的源代码的sn-p:

@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;
}

幻灯片菜单半打开

幻灯片菜单完全打开

幻灯片菜单关闭

【讨论】:

    猜你喜欢
    • 2017-12-17
    • 2018-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多