Effet Verre dépoli en JavaFX?


Je fais un projet JavaFX2/FXML sur le thème iOS7 et je me demandais comment je pourrais faire en sorte qu'un objet Rectangle ait un effet de verre dépoli de type iOS7.

J'aimerais aussi qu'il ait une petite ombre. C'est délicat, car vous pourriez être en mesure de voir l'ombre derrière les objets semi-transparents. J'aimerais juste qu'il soit présent sur les bords.

Est-ce possible? Voici une image montrant l'effet désiré (sans compter la petite ombre portée):

J'aimerais qu'elle ressemble à ceci

MISE À JOUR: Voici une suite du problème. Cela va avoir l'air incroyable: D.

Author: Community, 2014-03-25

1 answers

La Solution De L'Échantillon

gel

Exécutez le programme ci-dessous et faites défiler ou balayez vers le haut pour afficher la vitre.

Le but du programme est simplement d'échantillonner les techniques impliquées et non d'agir comme une bibliothèque à usage général pour l'effet de gel.

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

Image source

Enregistrez cette image parallèlement à la source Java en tant que fichier nommé {[3] } et demandez à votre système de construction de la copier dans le répertoire cible pour la sortie binaire du construire.

ios-capture d'écran

Réponses aux questions supplémentaires

"JDK 8", cela serait-il une exigence de cela?

L'exemple de code ci-dessus est écrit sur JDK 8. Le portage vers JDK 7 en remplaçant les appels lambda par des classes internes anonymes est assez trivial.

En général, Java 7 est assez daté pour le travail JavaFX. Je conseille de mettre à niveau au plus tôt pour travailler avec un minimum Java 8 version.

Initialisation de vos volets avec des arguments

Des constructeurs plus pratiques pour la plupart des nœuds parents sont une fonctionnalité Java 8. Vous pouvez facilement convertir le format Java 8:

 StackPane stack = new StackPane(child1, child2);

Vers Java 7:

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

Cela fonctionnera-t-il si le bureau est derrière un volet givré?

Pas directement, vous pouvez créer une nouvelle question pour que.

Mise à jour: Questions connexes

Utilisateur créé: Effet JavaFX sur background pour permettre à l'effet givré de s'appliquer à une fenêtre sur un fond d'écran.

Un autre utilisateur a créé: Comment créer une scène transparente JavaFX avec des ombres uniquement sur la bordure? pour appliquer un effet d'ombre halo autour de cette fenêtre.

 18
Author: jewelsea, 2017-05-23 11:53:02