2014-03-24 147 views
12

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

我也希望它有一个小影子。这很棘手,因为您可能会看到半透明对象背后的阴影。我只是想把它放在边缘。

这可能吗?这里是展示预期的效果(不包括小下拉阴影)图片:

I'd like it to look like this

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

回答

18

试样溶液

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,” 那会正好是这方面的一个要求?

上面的示例代码是针对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?在此窗口周围应用晕影效果。

+4

哦,该死的,JDK 8. – GGrec

+2

我很无语......那个效果看起来很美!它看起来比我使用的图像更冷。 @GGrec说“JDK 8”会不会成为这方面的要求? – Taconut

+0

@Taconut他在上面的例子中使用了lambda表达式。您可以简单地将它们替换为使用JDK 7进行编译。 – GGrec