javafx 遮罩_JavaFX技巧31:遮罩/剪切/ Alpha通道
javafx 遮罩
選擇條
最近,我不得不實現一個自定義控件,該控件使用戶可以從項目列表中選擇一個項目。 此“ SelectionStrip”控件必須水平放置項目,并且在項目過多的情況下,允許用戶左右水平滾動。 該控件將在空間受限的區域中使用,因此用于滾動的按鈕應僅在需要時顯示。 顯示時,它們也不應浪費任何額外的空間。 因此,我決定將它們放置在控件左側和右側的頂部。 所有這些都很容易實現,除了現在很難將滾動按鈕與項目區分開。 可以在下面的三個圖像中看到。
阿爾法頻道?
因此,我認為在靠近左側或右側邊緣時以某種方式淡出項目會很好。 這種行為通常可以通過使用alpha通道來完成。 隨著像素到邊緣的距離減小,可能會降低像素的不透明度。 好的.....但是在JavaFX中如何完成呢? 在相當長的一段時間里,我一直在研究各種“混合模式”,這些模式可以用來定義兩個重疊節點如何在彼此之上繪制。 但是,這是錯誤的方向。 事實證明,我已經知道該怎么做,因為我曾經寫過一篇博客文章,內容涉及剪輯以及填充和未填充剪輯之間的區別 。 但是我想這是很久以前的事了,我沒有在“填充”和“不透明度小于1”之間建立聯系。
復雜剪輯!
到目前為止,我用于自定義控件的大多數剪輯都是簡單的矩形。 他們通常確保到達其父控件的布局范圍之外的子節點不可見或僅部分可見。 但是此剪輯不同,它更加復雜。 它必須定義三個不同的區域。 左側為“淡入”區域,中間為“完全不透明”區域,右側為“淡出”區域。 為此,我定義了一個“組”,它由三個填充的“矩形”節點組成。 中心矩形的填充顏色為純黑色,而其他兩個矩形的填充顏色為從透明到黑色的線性漸變,反之亦然。 下圖說明了這一點。
通過此設置,我們現在可以將任何節點作為子節點添加到堆棧窗格中,并且將在其側面用淡入和淡出效果進行繪制。
結果
從一開始就將滾動箭頭/按鈕應用于“ SelectionStrip”控件后,它現在始終清晰可見,并且整體用戶體驗變得更加令人愉悅。 這些小細節使被認為是“學生項目”或“商業應用程序”的UI有所不同。 因此有時值得在這些上投入時間。
源代碼
我將屏蔽邏輯放入了一個稱為“ MaskedView”的自定義控件中。 在本文的底部,您將看到包含此??控件源代碼的Gist(或Gist鏈接)。 可以將其視為給定內容節點的包裝器。
import javafx.beans.property.DoubleProperty; import javafx.beans.property.SimpleDoubleProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.scene.Node; import javafx.scene.control.Control; import javafx.scene.control.Skin;public class MaskedView extends Control {public MaskedView(Node content) {setContent(content);}@Overrideprotected Skin<?> createDefaultSkin() {return new MaskedViewSkin(this);}private final SimpleObjectProperty<Node> content = new SimpleObjectProperty<>(this, "content");public final Node getContent() {return content.get();}public final SimpleObjectProperty<Node> contentProperty() {return content;}public final void setContent(Node content) {this.content.set(content);}private final DoubleProperty fadingSize = new SimpleDoubleProperty(this, "fadingSize", 120);public final double getFadingSize() {return fadingSize.get();}public final DoubleProperty fadingSizeProperty() {return fadingSize;}public final void setFadingSize(double fadingSize) {this.fadingSize.set(fadingSize);} }import javafx.beans.InvalidationListener; import javafx.beans.WeakInvalidationListener; import javafx.scene.Group; import javafx.scene.Node; import javafx.scene.control.SkinBase; import javafx.scene.layout.StackPane; import javafx.scene.paint.Color; import javafx.scene.paint.CycleMethod; import javafx.scene.paint.LinearGradient; import javafx.scene.paint.Stop; import javafx.scene.shape.Rectangle;public class MaskedViewSkin extends SkinBase {private final Rectangle leftClip;private final Rectangle rightClip;private final Rectangle centerClip;private final Group group;private final StackPane stackPane;public MaskedViewSkin(MaskedView view) {super(view);leftClip = new Rectangle();rightClip = new Rectangle();centerClip = new Rectangle();centerClip.setFill(Color.BLACK);leftClip.setManaged(false);centerClip.setManaged(false);rightClip.setManaged(false);group = new Group(leftClip, centerClip, rightClip);stackPane = new StackPane();stackPane.setManaged(false);stackPane.setClip(group);getChildren().add(stackPane);view.contentProperty().addListener((observable, oldContent, newContent) -> buildView(oldContent, newContent));buildView(null, view.getContent());view.widthProperty().addListener(it -> updateClip());view.fadingSizeProperty().addListener(it -> updateClip());}private final InvalidationListener translateXListener = it -> updateClip();private final WeakInvalidationListener weakTranslateXListener = new WeakInvalidationListener(translateXListener);private void buildView(Node oldContent, Node newContent) {if (oldContent != null) {stackPane.getChildren().clear();oldContent.translateXProperty().removeListener(weakTranslateXListener);}if (newContent != null) {stackPane.getChildren().setAll(newContent);newContent.translateXProperty().addListener(weakTranslateXListener);}updateClip();}private void updateClip() {final MaskedView view = getSkinnable();Node content = view.getContent();if (content != null) {final double fadingSize = view.getFadingSize();if (content.getTranslateX() < 0) { leftClip.setFill(new LinearGradient(0, 0, fadingSize, 0, false, CycleMethod.NO_CYCLE, new Stop(0, Color.TRANSPARENT), new Stop(1, Color.BLACK))); } else { leftClip.setFill(Color.BLACK); } if (content.getTranslateX() + content.prefWidth(-1) > view.getWidth()) {rightClip.setFill(new LinearGradient(0, 0, fadingSize, 0, false, CycleMethod.NO_CYCLE, new Stop(0, Color.BLACK), new Stop(1, Color.TRANSPARENT)));} else {rightClip.setFill(Color.BLACK);}}view.requestLayout();}@Overrideprotected void layoutChildren(double contentX, double contentY, double contentWidth, double contentHeight) {final double fadingSize = Math.min(contentWidth / 2, getSkinnable().getFadingSize());stackPane.resizeRelocate(snapPosition(contentX), snapPosition(contentY), snapSpace(contentWidth), snapSpace(contentHeight));resizeRelocate(leftClip, snapPosition(contentX), snapPosition(contentY), snapSpace(fadingSize), snapSpace(contentHeight));resizeRelocate(centerClip, snapPosition(contentX + fadingSize), snapPosition(contentY), snapSpace(contentWidth - 2 * fadingSize), snapSpace(contentHeight));resizeRelocate(rightClip, snapPosition(contentX + contentWidth - fadingSize), snapPosition(contentY), snapSpace(fadingSize), snapSpace(contentHeight));}private void resizeRelocate(Rectangle rect, double x, double y, double w, double h) {rect.setLayoutX(x);rect.setLayoutY(y);rect.setWidth(w);rect.setHeight(h);} }希望您能找到此控件的好用例。
祝大家編碼愉快!
翻譯自: https://www.javacodegeeks.com/2018/07/javafx-tip-31-masking-clipping-alpha-channel.html
javafx 遮罩
總結
以上是生活随笔為你收集整理的javafx 遮罩_JavaFX技巧31:遮罩/剪切/ Alpha通道的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 怎么才从光盘启动电脑上(用光盘怎么启动电
- 下一篇: 骁龙8gen2首发手机介绍(骁龙2系列处