代码之家  ›  专栏  ›  技术社区  ›  Taconut

JavaFX中的磨砂玻璃效果?

  •  15
  • Taconut  · 技术社区  · 10 年前

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

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

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

    I'd like it to look like this

    更新: Here's 该问题的延续。这看起来很神奇:D。

    1 回复  |  直到 7 年前
        1
  •  22
  •   Community Dai    7 年前

    样品溶液

    frost

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

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

    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 并让您的构建系统将其复制到目标目录,以获得构建的二进制输出。

    ios-screenshot

    其他问题的答案

    “JDK 8”,这会是这方面的要求吗?

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

    总的来说,Java7对于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? 以在该窗口周围应用光晕阴影效果。