【问题标题】:Frosted Glass Effect in JavaFX?JavaFX中的磨砂玻璃效果?
【发布时间】:2014-05-02 13:19:41
【问题描述】:

我正在制作一个以 iOS7 为主题的 JavaFX2/FXML 项目,我想知道如何使 Rectangle 对象具有类似 iOS7 的毛玻璃效果。

我也希望它有一个小阴影。这很棘手,因为您可能会看到半透明物体后面的阴影。我只是希望它出现在边缘。

这可能吗?这是一张显示所需效果的图片(不包括小阴影):

更新:Here's 问题的延续。这看起来会很棒:D。

【问题讨论】:

    标签: java user-interface ios7 javafx-2 blur


    【解决方案1】:

    示例解决方案

    运行下面的程序并向上滚动或滑动以显示玻璃窗格。

    该程序的目的只是对所涉及的技术进行采样,而不是作为霜效果的通用库。

    import javafx.animation.*;
    import javafx.application.Application;
    import javafx.beans.property.*;
    import javafx.geometry.Rectangle2D;
    import javafx.scene.*;
    import javafx.scene.Node;
    import javafx.scene.control.Label;
    import javafx.scene.effect.*;
    import javafx.scene.image.*;
    import javafx.scene.input.ScrollEvent;
    import javafx.scene.layout.*;
    import javafx.scene.paint.Color;
    import javafx.scene.shape.Rectangle;
    import javafx.stage.Stage;
    import javafx.util.Duration;
    
    // slides a frost pane in on scroll or swipe up; slides it out on scroll or swipe down.
    public class Frosty extends Application {
    
        private static final double W = 330;
        private static final double H = 590;
    
        private static final double BLUR_AMOUNT = 60;
        private static final Duration SLIDE_DURATION = Duration.seconds(0.4);
    
        private static final double UPPER_SLIDE_POSITION = 100;
    
        private static final Effect frostEffect =
            new BoxBlur(BLUR_AMOUNT, BLUR_AMOUNT, 3);
    
        @Override public void start(Stage stage) {
            DoubleProperty y = new SimpleDoubleProperty(H);
    
            Node background = createBackground();
            Node frost      = freeze(background, y);
            Node content    = createContent();
            content.setVisible(false);
    
            Scene scene = new Scene(
                    new StackPane(
                            background,
                            frost,
                            content
                    )
            );
    
            stage.setScene(scene);
            stage.show();
    
            addSlideHandlers(y, content, scene);
        }
    
        // create a background node to be frozen over.
        private Node createBackground() {
            Image backgroundImage = new Image(
                    getClass().getResourceAsStream("ios-screenshot.png")
            );
            ImageView background = new ImageView(backgroundImage);
            Rectangle2D viewport = new Rectangle2D(0, 0, W, H);
            background.setViewport(viewport);
    
            return background;
        }
    
        // create some content to be displayed on top of the frozen glass panel.
        private Label createContent() {
            Label label = new Label("The overlaid text is clear and the background below is frosty.");
    
            label.setStyle("-fx-font-size: 25px; -fx-text-fill: midnightblue;");
            label.setEffect(new Glow());
            label.setMaxWidth(W - 20);
            label.setWrapText(true);
    
            return label;
        }
    
        // add handlers to slide the glass panel in and out.
        private void addSlideHandlers(DoubleProperty y, Node content, Scene scene) {
            Timeline slideIn = new Timeline(
                    new KeyFrame(
                            SLIDE_DURATION,
                            new KeyValue(
                                    y,
                                    UPPER_SLIDE_POSITION
                            )
                    )
            );
    
            slideIn.setOnFinished(e -> content.setVisible(true));
    
            Timeline slideOut = new Timeline(
                    new KeyFrame(
                            SLIDE_DURATION,
                            new KeyValue(
                                    y,
                                    H
                            )
                    )
            );
    
            scene.setOnSwipeUp(e -> {
                slideOut.stop();
                slideIn.play();
            });
    
            scene.setOnSwipeDown(e -> {
                slideIn.stop();
                slideOut.play();
                content.setVisible(false);
            });
    
            // scroll handler isn't necessary if you have a touch screen.
            scene.setOnScroll((ScrollEvent e) -> {
                if (e.getDeltaY() < 0) {
                    slideOut.stop();
                    slideIn.play();
                } else {
                    slideIn.stop();
                    slideOut.play();
                    content.setVisible(false);
                }
            });
        }
    
        // create a frosty pane from a background node.
        private StackPane freeze(Node background, DoubleProperty y) {
            Image frostImage = background.snapshot(
                    new SnapshotParameters(),
                    null
            );
            ImageView frost = new ImageView(frostImage);
    
            Rectangle filler = new Rectangle(0, 0, W, H);
            filler.setFill(Color.AZURE);
    
            Pane frostPane = new Pane(frost);
            frostPane.setEffect(frostEffect);
    
            StackPane frostView = new StackPane(
                    filler,
                    frostPane
            );
    
            Rectangle clipShape = new Rectangle(0, y.get(), W, H);
            frostView.setClip(clipShape);
    
            clipShape.yProperty().bind(y);
    
            return frostView;
        }
    
        public static void main(String[] args) { launch(args); }
    }  
    

    源图片

    将此图像与 Java 源代码并行保存为一个名为 ios-screenshot.png 的文件,并让您的构建系统将其复制到目标目录,以获取构建的二进制输出。

    其他问题的答案

    “JDK 8”会是这个要求吗?

    上面的示例代码是针对 JDK 8 编写的。通过用匿名内部类替换 lambda 调用将其移植回 JDK 7 非常简单。

    一般来说,Java 7 对于 JavaFX 工作来说已经过时了。我建议您尽早升级以使用 Java 8 最低版本。

    使用参数启动窗格

    对于大多数父节点来说,更方便的构造函数是Java 8 feature。您可以轻松转换 Java 8 格式:

     StackPane stack = new StackPane(child1, child2);
    

    到 Java 7:

     StackPane stack = new StackPane();
     stack.getChildren().setAll(child1, child2);
    

    如果桌面位于结霜的窗格后面,这会起作用吗?

    不是直接的,您可以为此创建一个新问题。

    更新:相关问题

    用户创建:JavaFX effect on background 允许将磨砂效果应用于桌面背景上的窗口。

    另一个用户创建了:How do I create a JavaFX transparent stage with shadows on only the border? 在此窗口周围应用光晕阴影效果。

    【讨论】:

    • 我无语了……这个效果看起来很漂亮!它看起来比我使用的图像更冷淡。 @GGrec 说“JDK 8”,这恰好是这个要求吗?
    • @Taconut 他在上面的例子中使用了 lambda 表达式。您可以简单地替换它们以使用 JDK 7 进行编译。
    • 我让它在没有 lambda 的情况下工作,但你正在用参数启动你的窗格。那是怎么回事?此外,如果桌面位于结霜的窗格后面,这会起作用吗?
    • 更新答案以解决其他问题。
    • 它似乎按照我的设计工作正常。它可能与 iOS 7 不完全一样,因为我从未使用过 iOS 7。这只是一个概念证明。您可以使用编辑按钮对其进行修改以进行任何您希望的更改。
    猜你喜欢
    • 1970-01-01
    • 2012-07-21
    • 2019-04-16
    • 1970-01-01
    • 1970-01-01
    • 2021-11-12
    • 2020-02-03
    • 1970-01-01
    • 2017-09-18
    相关资源
    最近更新 更多