Jose Teixeira
Jose Teixeira

Reputation: 19

UI Popup Opacity Mask JavaFX

Is it possible with Popup opacity mask top and bottom JavaFX? I have TextField autocomplete with Popup. So the idea is to put an opacity mask.

Upvotes: 1

Views: 169

Answers (1)

Sai Dandem
Sai Dandem

Reputation: 9969

Below is another way you can give a try, for getting the opacity masked effect. Though it is not exactly the same implementation, I took some ideas from the link you provided :).

I created a small utility where you can pass the Popup instance. The utility builds the mask panes and include to the root node of the Popup.

enter image description here

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.stage.Popup;
import javafx.stage.Stage;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class PopupOpacityMaskDemo extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        StackPane root = new StackPane();
        root.setStyle("-fx-background-color:grey;");
        root.setOnMouseClicked(e -> {
            ListView<String> content = new ListView<>();
            content.getItems().addAll(IntStream.range(100, 200).mapToObj(i -> i + "").collect(Collectors.toList()));
            content.setPrefSize(200, 250);

            Popup popup = new Popup();
            popup.setAutoHide(true);
            popup.getContent().add(content);
            popup.setX(e.getScreenX());
            popup.setY(e.getScreenY());
            popup.show(root.getScene().getWindow());
            MaskUtil.applyMask(popup);
        });
        Scene scene = new Scene(root, 200, 200);
        primaryStage.setScene(scene);
        primaryStage.setTitle("Demo");
        primaryStage.show();
    }

    static class MaskUtil{
        static void applyMask(Popup popup) {
            double fadeSize = 70;
            Pane pane = (Pane)popup.getScene().getRoot();

            // Build the mask panes
            Pane topMask = buildMaskPane(pane, fadeSize, false);
            Pane bottomMask = buildMaskPane(pane, fadeSize, true);

            // Just ensuring to remove any masks (if you are reusing the Popup)
            pane.getChildren().removeAll(pane.lookupAll(".mask"));
            pane.getChildren().addAll(topMask, bottomMask);

            // Update the bottom mask position by listening to height of pane
            pane.heightProperty().addListener((obs, old, h) -> bottomMask.setLayoutY(h.doubleValue() - fadeSize));
            if (pane.getHeight() > 0) {
                bottomMask.setLayoutY(pane.getHeight() - fadeSize);
            }
        }

        private static Pane buildMaskPane(Pane pane, double fadeSize, boolean isBottom) {
            Pane mask = new Pane();
            mask.setMouseTransparent(true); // Turn this to 'false' if you don't want to interact over mask
            mask.setPrefHeight(fadeSize);
            mask.prefWidthProperty().bind(pane.widthProperty());
            mask.maxHeightProperty().bind(mask.prefHeightProperty());
            mask.minHeightProperty().bind(mask.prefHeightProperty());
            mask.getStyleClass().add("mask");
            mask.setStyle(String.format("-fx-background-color:linear-gradient(to %s, #555555, transparent)", isBottom ? "top" : "bottom"));
            return mask;
        }
    }
}

Upvotes: 3

Related Questions