JavaFX矩形到圆形动画

JavaFX矩形到圆形动画,java,javafx,javafx-8,Java,Javafx,Javafx 8,我有一个矩形窗格,我用它作为横幅,在我的主屏幕应用程序的舞台上垂直放置图标。当前,当我单击图标时,我使用一个过渡将窗格向上滑动(脱离屏幕),在图标下创建一个圆形,然后将图标和圆形一起移动到右上角。单击角落中的图标可反转动画并将我带回主屏幕 我想让我的窗格在图标所在的位置转换成圆形,而不是向上滑动窗格 我不介意将我的窗格设置为透明,创建一个矩形形状,然后将该矩形转换为圆形-我认为这更可行 不过,我还没有找到任何将一种形状转换为另一种形状的清晰示例。我发现这是一个很好的例子,但它适用于iOS: 有什

我有一个矩形窗格,我用它作为横幅,在我的主屏幕应用程序的舞台上垂直放置图标。当前,当我单击图标时,我使用一个过渡将窗格向上滑动(脱离屏幕),在图标下创建一个圆形,然后将图标和圆形一起移动到右上角。单击角落中的图标可反转动画并将我带回主屏幕

我想让我的窗格在图标所在的位置转换成圆形,而不是向上滑动窗格

我不介意将我的窗格设置为透明,创建一个矩形形状,然后将该矩形转换为圆形-我认为这更可行

不过,我还没有找到任何将一种形状转换为另一种形状的清晰示例。我发现这是一个很好的例子,但它适用于iOS:

有什么建议吗?我真的只需要一个将矩形形状变成圆形的小示例动画


谢谢

考虑设置区域剪辑的动画。您可以将其与翻译相结合,将“菜单”移动到右上角。下面是一个简单的例子:

import java.util.Random;

import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.geometry.Bounds;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.stage.Stage;
import javafx.util.Duration;

public class AnimatingIconMenu extends Application {

    private BorderPane root ;

    @Override
    public void start(Stage primaryStage) {
        HBox menu = new HBox(10);
        BorderPane.setMargin(menu, new Insets(10));
        menu.setAlignment(Pos.CENTER);

        for (int i = 1; i <= 4 ; i++) {
            Option opt = new Option("Choice "+i);
            opt.selectedProperty().addListener((obs, wasSelected, isNowSelected) -> {

                Node view = opt.getView();
                Bounds b = view.getBoundsInParent();

                Rectangle clip = new Rectangle();
                Timeline timeline = new Timeline();
                Duration duration = Duration.seconds(0.66);

                if (isNowSelected) {

                    clip.setWidth(menu.getWidth());
                    clip.setHeight(menu.getHeight());

                    timeline.getKeyFrames().add(new KeyFrame(duration, 
                        new KeyValue(clip.xProperty(), b.getMinX()),
                        new KeyValue(clip.yProperty(), b.getMinY()),
                        new KeyValue(clip.widthProperty(), b.getWidth()),
                        new KeyValue(clip.heightProperty(), b.getHeight()), 
                        new KeyValue(clip.arcWidthProperty(), Math.min(b.getWidth(), b.getHeight())),
                        new KeyValue(clip.arcHeightProperty(), Math.min(b.getWidth(), b.getHeight())),
                        new KeyValue(menu.translateXProperty(), menu.getWidth() - b.getMaxX())));

                    timeline.setOnFinished(e -> showPage(opt));

                } else {

                    clip.setWidth(b.getWidth());
                    clip.setHeight(b.getHeight());
                    clip.setX(b.getMinX());
                    clip.setY(b.getMinY());
                    clip.setArcWidth(Math.min(b.getWidth(), b.getHeight()));
                    clip.setArcHeight(Math.min(b.getWidth(), b.getHeight()));

                    timeline.getKeyFrames().add(new KeyFrame(duration,
                        new KeyValue(clip.xProperty(), 0),
                        new KeyValue(clip.yProperty(), 0),
                        new KeyValue(clip.widthProperty(), menu.getWidth()),
                        new KeyValue(clip.heightProperty(), menu.getHeight()),
                        new KeyValue(clip.arcHeightProperty(), 0),
                        new KeyValue(clip.arcWidthProperty(), 0),
                        new KeyValue(menu.translateXProperty(), 0)));

                    timeline.setOnFinished(e -> showHome());
                }
                menu.setClip(clip);

                timeline.play();
            });
            menu.getChildren().add(opt.getView());
        }

        root = new BorderPane();
        showHome();
        root.setTop(menu);
        primaryStage.setScene(new Scene(root, 800, 600));
        primaryStage.show();

    }

    private void showPage(Option option) {

        Label label = new Label(option.getOptionText());
        label.setFont(Font.font("sans-serif", FontWeight.BOLD, 48));
        root.setCenter(label);
    }

    private void showHome() {
        Label label = new Label("Home");
        label.setFont(Font.font("sans-serif", FontWeight.BOLD, 48));
        root.setCenter(label);
    }

    public static class Option {

        private BooleanProperty selected = new SimpleBooleanProperty();

        private final String optionText ;
        private final Label view ;

        public Option(String optionText) {
            this.optionText = optionText ;
            this.view = new Label(optionText);
            view.setAlignment(Pos.CENTER);
            view.setWrapText(true);
            view.setPrefSize(80, 80);
            view.setStyle("-fx-background-color: -fx-background; -fx-background: "+randomColor()+";"); 
            view.setOnMouseClicked(e -> setSelected(!isSelected()));
        }

        public Node getView() {
            return view ;
        }

        public String getOptionText() {
            return optionText ;
        }

        private String randomColor() {
            Random rng = new Random();
            int r = rng.nextInt(256);
            int g = rng.nextInt(256);
            int b = rng.nextInt(256);
            return String.format("#%02x%02x%02x", r, g, b);
        }

        public final BooleanProperty selectedProperty() {
            return this.selected;
        }


        public final boolean isSelected() {
            return this.selectedProperty().get();
        }


        public final void setSelected(final boolean selected) {
            this.selectedProperty().set(selected);
        }


    }

    public static void main(String[] args) {
        launch(args);
    }
}
import java.util.Random;
导入javafx.animation.KeyFrame;
导入javafx.animation.KeyValue;
导入javafx.animation.Timeline;
导入javafx.application.application;
导入javafx.beans.property.BooleanProperty;
导入javafx.beans.property.SimpleBoleAnProperty;
导入javafx.geometry.Bounds;
导入javafx.geometry.Insets;
导入javafx.geometry.Pos;
导入javafx.scene.Node;
导入javafx.scene.scene;
导入javafx.scene.control.Label;
导入javafx.scene.layout.BorderPane;
导入javafx.scene.layout.HBox;
导入javafx.scene.shape.Rectangle;
导入javafx.scene.text.Font;
导入javafx.scene.text.FontWeight;
导入javafx.stage.stage;
导入javafx.util.Duration;
公共类AnimatingIconMenu扩展了应用程序{
私有边界根;
@凌驾
公共无效开始(阶段primaryStage){
HBox菜单=新HBox(10);
边框窗格。设置边距(菜单,新插图(10));
菜单设置对齐(位置中心);
对于(int i=1;i{
节点视图=opt.getView();
Bounds b=view.getBoundsInParent();
矩形剪辑=新矩形();
时间线=新时间线();
持续时间=持续时间。秒(0.66);
如果(现在已选定){
clip.setWidth(menu.getWidth());
clip.setHeight(menu.getHeight());
timeline.getKeyFrames().add(新关键帧(持续时间,
新的键值(clip.xProperty(),b.getMinX()),
新的键值(clip.yProperty(),b.getMinY()),
新的键值(clip.widthProperty(),b.getWidth()),
新的键值(clip.heightProperty(),b.getHeight()),
新的键值(clip.arcWidthProperty(),Math.min(b.getWidth(),b.getHeight()),
新的键值(clip.arcHeightProperty()、Math.min(b.getWidth()、b.getHeight()),
新的键值(menu.translateProperty(),menu.getWidth()-b.getMaxX());
timeline.setOnFinished(e->showPage(opt));
}否则{
clip.setWidth(b.getWidth());
clip.setHeight(b.getHeight());
clip.setX(b.getMinX());
clip.setY(b.getMinY());
clip.setArcWidth(Math.min(b.getWidth(),b.getHeight());
clip.setArcHeight(Math.min(b.getWidth(),b.getHeight());
timeline.getKeyFrames().add(新关键帧(持续时间,
新的键值(clip.xProperty(),0),
新的键值(clip.yProperty(),0),
新键值(clip.widthProperty(),menu.getWidth()),
新键值(clip.heightProperty(),menu.getHeight()),
新键值(clip.arcHeightProperty(),0),
新的键值(clip.arcWidthProperty(),0),
新的键值(menu.translateProperty(),0));
timeline.setOnFinished(e->showHome());
}
菜单.setClip(clip);
timeline.play();
});
menu.getChildren().add(opt.getView());
}
root=新边框窗格();
showHome();
root.setTop(菜单);
初始阶段。设置场景(新场景(根,800600));
primaryStage.show();
}
私有无效显示页(选项){
Label Label=新标签(option.getOptionText());
label.setFont(Font.Font(“sans serif”,fontwweight.BOLD,48));
根。设置中心(标签);
}
私人空间展示之家(){
标签=新标签(“主页”);
label.setFont(Font.Font(“sans serif”,fontwweight.BOLD,48));
根。设置中心(标签);
}
公共静态类选项{
选定的私有布尔属性=新的SimpleBoleAnProperty();
私有最终字符串optionText;
私有最终标签视图;
公共选项(字符串optionText){
this.optionText=optionText;
this.view=新标签(optionText);
视图。设置对齐(位置中心);
view.setWrapText(true);
view.setPrefSize(80,80);
view.setStyle(“-fx背景颜色:-fx背景;-fx背景:“+randomColor()+”;”);
view.setOnMouseClicked(e->setSelected(!isSelected());
}
公共节点getView(){
返回视图;
}
公共字符串getOptionText(){
返回optionText;
}
私有字符串randomColor(){
随机rng=新随机();
int r=rng.nextInt(256);
int g=rng.nextInt(256);
int b=rng.nextInt(256);
返回字符串。格式(“#%02x%02x%02x”,r,g