JavaFX 中的磨砂玻璃效果? [英] Frosted Glass Effect in JavaFX?

查看:48
本文介绍了JavaFX 中的磨砂玻璃效果?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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

更新:

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

该程序的目的只是对所涉及的技术进行采样,而不是充当霜冻效果的通用库.

import javafx.animation.*;导入 javafx.application.Application;导入 javafx.beans.property.*;导入 javafx.geometry.Rectangle2D;导入 javafx.scene.*;导入 javafx.scene.Node;导入 javafx.scene.control.Label;导入 javafx.scene.effect.*;导入 javafx.scene.image.*;导入 javafx.scene.input.ScrollEvent;导入 javafx.scene.layout.*;导入 javafx.scene.paint.Color;导入 javafx.scene.shape.Rectangle;导入 javafx.stage.Stage;导入 javafx.util.Duration;//在滚动或向上滑动时滑动一个冰霜窗格;在滚动或向下滑动时将其滑出.公共类 Frosty 扩展应用程序 {私人静态最终双 W = 330;私人静态最终双H = 590;私人静态最终双 BLUR_AMOUNT = 60;私人静态最终持续时间 SLIDE_DURATION = Duration.seconds(0.4);私人静态最终双UPPER_SLIDE_POSITION = 100;私有静态最终效果frostEffect =新 BoxBlur(BLUR_AMOUNT, BLUR_AMOUNT, 3);@Override public void start(Stage stage) {DoubleProperty y = new SimpleDoubleProperty(H);节点背景 = createBackground();节点霜 = 冻结(背景,y);节点内容 = createContent();content.setVisible(false);场景场景 = 新场景(新的堆栈窗格(背景,霜,内容));stage.setScene(场景);舞台表演();addSlideHandlers(y, 内容, 场景);}//创建一个要冻结的背景节点.私有节点 createBackground() {图像背景图像 = 新图像(getClass().getResourceAsStream("ios-screenshot.png"));ImageView background = new ImageView(backgroundImage);Rectangle2D 视口 = new Rectangle2D(0, 0, W, H);background.setViewport(视口);返回背景;}//创建一些要显示在冻结玻璃面板顶部的内容.私有标签 createContent() {Label label = new Label("覆盖的文字清晰,下方背景冷淡.");label.setStyle("-fx-font-size: 25px; -fx-text-fill:midnightblue;");label.setEffect(new Glow());label.setMaxWidth(W - 20);label.setWrapText(true);退货标签;}//添加处理程序来滑入和滑出玻璃面板.私有无效 addSlideHandlers(DoubleProperty y,节点内容,场景场景){时间线滑入 = 新时间线(新的关键帧(SLIDE_DURATION,新的键值(是,UPPER_SLIDE_POSITION)));slideIn.setOnFinished(e -> content.setVisible(true));时间线滑出 = 新时间线(新的关键帧(SLIDE_DURATION,新的键值(是,H)));scene.setOnSwipeUp(e -> {滑出.停止();幻灯片播放();});scene.setOnSwipeDown(e -> {滑入.停止();幻灯片播放();content.setVisible(false);});//如果您有触摸屏,则不需要滚动处理程序.scene.setOnScroll((ScrollEvent e) -> {如果 (e.getDeltaY() <0) {滑出.停止();幻灯片播放();} 别的 {滑入.停止();幻灯片播放();content.setVisible(false);}});}//从背景节点创建一个冷淡的窗格.私有 StackPane 冻结(节点背景,DoubleProperty y){图像frozenImage = background.snapshot(新快照参数(),空值);ImageViewfrost = new ImageView(frostImage);矩形填充器 = new Rectangle(0, 0, W, H);填充物.setFill(颜色.天蓝色);窗格frostPane = 新窗格(frost);frostPane.setEffect(frostEffect);StackPanefrostView = new StackPane(填料,冰霜窗格);矩形clipShape = new Rectangle(0, y.get(), W, H);frostView.setClip(clipShape);clipShape.yProperty().bind(y);返回frostView;}公共静态无效主(字符串 [] args){ 启动(参数);}}

源图片

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

其他问题的答案

<块引用>

JDK 8",这会是这个的要求吗?

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

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

<块引用>

使用参数启动您的窗格

对于大多数父节点更方便的构造函数是 Java 8 特性.您可以轻松转换 Java 8 格式:

 StackPane stack = new StackPane(child1, child2);

到 Java 7:

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

<块引用>

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

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

更新:相关问题

用户创建:​​背景上的 JavaFX 效果 允许将磨砂效果应用于窗口在桌面背景上.

另一个用户创建:如何创建仅在边框上带有阴影的 JavaFX 透明舞台? 在此窗口周围应用光晕阴影效果.

I'm making an iOS7-themed JavaFX2/FXML project and I was wondering how I could make a Rectangle object have a iOS7-like frosted glass effect.

I'd also like it to have a small shadow. This is tricky, since you might be able to see the shadow behind the semi-transparent object. I'd just like it to be present around the edges.

Is this possible? Here's a picture showing the desired effect (not including the small drop-shadow):

UPDATE: Here's a continuation of the issue. This is going to look amazing :D.

解决方案

Sample Solution

Run the program below and scroll or swipe up to show the glass pane.

The purpose of the program is just to sample the techniques involved not to act as a general purpose library for the frost effect.

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

Source image

Save this image parallel to the Java source as a file named ios-screenshot.png and have your build system copy it to the target directory for the binary output of the build.

Answers to additional questions

"JDK 8," would that happen to be a requirement of this?

The sample code above is written against JDK 8. Porting it back to JDK 7 by replacing the lambda calls with anonymous inner classes is pretty trivial.

In general, Java 7 is pretty dated for JavaFX work. I advise upgrading at your earliest convenience to work with a Java 8 minimum version.

initiating your Panes with arguments

More convenient constructors for most parent nodes is a Java 8 feature. You can easily convert the Java 8 format:

 StackPane stack = new StackPane(child1, child2);

To Java 7:

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

will this working if the desktop is behind a frosty pane?

Not directly, you can create a new question for that.

Update: Related Questions

User created: JavaFX effect on background to allow the frosted effect to apply to a window over a desktop background.

Another user created: How do I create a JavaFX transparent stage with shadows on only the border? to apply a halo shadow effect around this window.

这篇关于JavaFX 中的磨砂玻璃效果?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆