如何在Java FX中更改布局和动画?

时间:2015-03-22 13:39:08

标签: animation layout javafx

我希望应用程序左侧的菜单在用户选择切换按钮时滑入框架,并在未选择切换按钮时再次退出。

我实现了我想要的一切,但我遇到的问题是布局不随动画而改变。

当菜单超出框架(你看不到它)时,布局就像它在框架中一样。

这是我菜单的初始化:

modulesBar = new ModulesBar();
modulesBar.setTranslateX(-250);
GridPane.setMargin(modulesBar, new Insets(10, 0, 0, 5));
GridPane.setRowSpan(modulesBar, GridPane.REMAINING);
root.add(modulesBar, 0, 1);

这是切换方法:

Timeline modulesBarAnimation = new Timeline();

if (mainBar.getModulesButton().isSelected()) {
    modulesBarAnimation.getKeyFrames().add(new KeyFrame(Duration.millis(250), new KeyValue(modulesBar.translateXProperty(), 0)));
} else {
    modulesBarAnimation.getKeyFrames().add(new KeyFrame(Duration.millis(250), new KeyValue(modulesBar.translateXProperty(), -250)));
}
modulesBarAnimation.playFromStart();

我也尝试使用setLayoutX(),但这并没有将菜单移出框架......

如何通过翻译更改布局?最好的是与动画相结合的平滑变化。

2 个答案:

答案 0 :(得分:2)

布局中不考虑Node上的任何变换。 (这是故意的;除了其他功能之外,它允许您修改Node相对于其通常布局位置的位置。)您的动画通过修改标准平移变换来工作;因此,这不会改变布局。

为了获得所需的效果,您需要动画来修改用于计算布局的属性。例如,由于您似乎使用的是GridPane,因此您可以将ColumnConstraints应用于GridPane并修改其中一列的prefWidth

SSCCE:

import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.value.ObservableBooleanValue;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;


public class AnimatingGridPane extends Application {

    @Override
    public void start(Stage primaryStage) {

        GridPane root = new GridPane();

        ColumnConstraints leftCol = new ColumnConstraints();
        leftCol.setPrefWidth(100);

        ColumnConstraints rightCol = new ColumnConstraints();

        root.getColumnConstraints().addAll(leftCol, rightCol);

        ObservableBooleanValue expanded = leftCol.prefWidthProperty().greaterThan(0);

        Button expandButton = new Button("");
        expandButton.textProperty().bind(
            Bindings.when(expanded).then("Hide options").otherwise("Show options"));

        expandButton.setOnAction(event -> {
            KeyFrame start ;
            KeyFrame end ;

            if (expanded.get()) {
                start = new KeyFrame(Duration.ZERO, new KeyValue(leftCol.prefWidthProperty(), 100));
                end = new KeyFrame(Duration.millis(250), new KeyValue(leftCol.prefWidthProperty(), 0));
            } else {
                start = new KeyFrame(Duration.ZERO, new KeyValue(leftCol.prefWidthProperty(), 0));
                end = new KeyFrame(Duration.millis(250) ,new KeyValue(leftCol.prefWidthProperty(), 100));                    
            }

            Timeline timeline = new Timeline(start, end);

            timeline.play();
        });

        Node content = createContent();

        root.setVgap(5);
        root.add(content, 1, 0);

        Region optionsPane = createOptionsPane();

        root.add(optionsPane, 0, 0);

        optionsPane.visibleProperty().bind(expanded);

        optionsPane.setPadding(new Insets(10));

        GridPane.setHalignment(expandButton, HPos.CENTER);
        root.add(expandButton, 1, 1);

        Scene scene = new Scene(root, 600, 400);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private GridPane createContent() {
        GridPane contentPane = new GridPane();

        contentPane.setHgap(5);
        contentPane.setVgap(5);

        contentPane.addRow(0, new Label("First Name:"),  new TextField());
        contentPane.addRow(1, new Label("Last Name:"),  new TextField());
        contentPane.addRow(2, new Label("Email:"),  new TextField());

        ColumnConstraints leftCol = new ColumnConstraints();
        leftCol.setHgrow(Priority.NEVER);
        leftCol.setHalignment(HPos.RIGHT);

        ColumnConstraints rightCol = new ColumnConstraints();
        rightCol.setHgrow(Priority.ALWAYS);
        rightCol.setFillWidth(true);

        contentPane.getColumnConstraints().addAll(leftCol, rightCol);
        return contentPane;
    }

    private Region createOptionsPane() {
        VBox optionsPane = new VBox(10, 
                createLabel("New"),
                createLabel("Open"),
                createLabel("Edit"),
                createLabel("Delete")
            );
        return optionsPane;
    }

    private Label createLabel(String text) {
        Label label = new Label(text);
        label.setEllipsisString("");
        return label ;
    }

    public static void main(String[] args) {
        launch(args);
    }
}

答案 1 :(得分:0)

翻译不会影响布局,您必须使用影响布局的方法。

(在这种情况下)使用modulesBar更改setPrefWidth(...)的宽度会影响布局并获得所需的结果。

菜单初始化的代码如下:

modulesBar = new ModulesBar();
modulesBar.setPrefWidth(0);
modulesBar.setMinWidth(0);
modulesBar.setTranslateX(-200);
GridPane.setMargin(modulesBar, new Insets(10, 0, 0, 5));
root.add(modulesBar, 0, 1);

更改宽度不会使setTranslateX()变得多余,仍然需要让按钮移出屏幕,否则它们只会调整到最小尺寸。

动画方法的代码如下:

private void switchModulesBar() {
    // Slides in the modules bar when "Modules"-toggle button is pressed
    if (mainBar.getModulesButton().isSelected()) {
        Animation modulesBarAnimation = new Transition() {
            {
                setCycleDuration(Duration.millis(250));
            }

            @Override
            protected void interpolate(double frac) {
                final double curWidth = 200 * frac;
                modulesBar.setPrefWidth(curWidth);
                modulesBar.setTranslateX(-200 + curWidth);
            }
        };
        modulesBarAnimation.play();
    } else { // Slides out the modules bar 
        Animation modulesBarAnimation = new Transition() {
            {
                setCycleDuration(Duration.millis(250));
            }

            @Override
            protected void interpolate(double frac) {
                final double curWidth = 200 * (1.0 - frac);
                modulesBar.setPrefWidth(curWidth);
                modulesBar.setTranslateX(-200 + curWidth);
            }
        };
        modulesBarAnimation.play();
    }
}