具有 PerspectiveTransform 的 JavaFX 翻转节点

标签 java javafx javafx-2 flip

JavaFX 2.x

我想做什么:

  • This script翻译成Java源代码。我自己尝试过,但其中一些内容已被弃用(例如 PerspectiveTransform#time - 在 JavaFX 2.2 中找不到)
  • 翻转 like thislike that .

    我不想做的事:

  • 使用 RotateTransition 因为它依赖于 PerspectiveCamera。由于我会有许多彼此相邻的可翻转图 block ,因此动画中途的前/后替换不会很顺利。

    我目前拥有的:

    import javafx.animation.KeyFrame;
    import javafx.animation.KeyValue;
    import javafx.animation.Timeline;
    import javafx.application.Application;
    import javafx.beans.property.SimpleDoubleProperty;
    import javafx.event.ActionEvent;
    import javafx.event.EventHandler;
    import javafx.scene.Group;
    import javafx.scene.Node;
    import javafx.scene.Scene;
    import javafx.scene.effect.PerspectiveTransform;
    import javafx.scene.effect.PerspectiveTransformBuilder;
    import javafx.scene.image.ImageView;
    import javafx.scene.input.MouseEvent;
    import javafx.scene.layout.StackPane;
    import javafx.stage.Stage;
    import javafx.util.Duration;
    
    /**
     * 
     * @author ggrec
     *
     */
    public class FX_Tester extends Application 
    {
    
        @Override
        public void start(final Stage stage) throws Exception 
        {
            final StackPane stackPane = new StackPane();
    
            final ImageView img1 = new ImageView("http://img3.wikia.nocookie.net/__cb20120816162009/mario/images/thumb/1/15/MarioNSMB2.png/200px-MarioNSMB2.png");
            final ImageView img2 = new ImageView("http://img2.wikia.nocookie.net/__cb20120518002849/mario/images/thumb/7/78/Tanooki_Mario_Artwork_-_Super_Mario_Bros._3.png/180px-Tanooki_Mario_Artwork_-_Super_Mario_Bros._3.png");
    
            final FlipView flipPane = new FlipView(img1, img2);
    
            stackPane.setOnMouseClicked(new EventHandler<MouseEvent>() {
    
                @Override public void handle(final MouseEvent arg0) 
                {
                    flipPane.doFlip();
                }
            });
    
            stackPane.getChildren().setAll(flipPane);
    
            stage.setScene(new Scene(stackPane));
            stage.show();
        }
    
        public static void main(final String[] args)
        {
            launch();
        }
    
        private class FlipView extends Group
        {
            private Node frontNode;
            private Node backNode;
    
            private boolean isFlipped = false;
    
            private SimpleDoubleProperty time = new SimpleDoubleProperty(Math.PI / 2);
    
            private Timeline anim = new Timeline(
    
                    new KeyFrame(Duration.ZERO, new KeyValue(time, Math.PI / 2)),
                    new KeyFrame(Duration.ONE,  new KeyValue(time, - Math.PI / 2)),
                    new KeyFrame(Duration.ONE,  new EventHandler<ActionEvent>() {
    
                        @Override public void handle(final ActionEvent arg0)
                        {
                            isFlipped = !isFlipped;
                        }
                    })
                    );
    
            private FlipView(final Node frontNode, final Node backNode)
            {
                this.frontNode = frontNode;
                this.backNode = backNode;
    
                getChildren().setAll(frontNode, backNode);
    
                frontNode.setEffect(getPT(time.doubleValue()));
                backNode.setEffect(getPT(time.doubleValue()));
    
                frontNode.visibleProperty().bind(time.greaterThan(0));
                backNode.visibleProperty().bind(time.lessThan(0));
            }
    
            private PerspectiveTransform getPT(final double t)
            {
                final double width = 200;
                final double height = 200;
                final double radius = width / 2;
                final double back = height / 10;
    
                return PerspectiveTransformBuilder.create()
                        .ulx(radius - Math.sin(t)*radius)
                        .uly(0 - Math.cos(t)*back)
                        .urx(radius + Math.sin(t)*radius)
                        .ury(0 + Math.cos(t)*back)
                        .lrx(radius + Math.sin(t)*radius)
                        .lry(height - Math.cos(t)*back)
                        .llx(radius - Math.sin(t)*radius)
                        .lly(height + Math.cos(t)*back)
                        .build();
            }
    
            public void doFlip() 
            {
                if (isFlipped)
                {
                    anim.setRate(1.0);
                    anim.setDelay(Duration.ZERO);
                }
                else
                {
                    anim.setRate(-1.0);
                    anim.setDelay(Duration.ONE);
                }
    
                anim.play();
            }
        }
    
    }
    
  • 最佳答案

    经过大量的研发,我设法实现了翻转功能没有 PerspectiveCamera,使用 PerspectiveTransform .

    如果您懒得运行这个 SSCCE,那么 go here to see a demo on how the below code works .

    问:但是乔治,这与其他方法有何不同???
    A: 首先:由于您没有使用 PerspectiveCamera,如果假设您在屏幕上有 100 个翻转图 block ,则用户的视角不会受到影响。第二个也是最后一个:后节点 已经翻转。所以它没有镜像,没有旋转,没有缩放。这是正常的”。是不是很棒?

    干杯。


    import javafx.animation.Interpolator;
    import javafx.animation.KeyFrame;
    import javafx.animation.KeyValue;
    import javafx.animation.Timeline;
    import javafx.application.Application;
    import javafx.beans.property.SimpleBooleanProperty;
    import javafx.beans.property.SimpleDoubleProperty;
    import javafx.beans.value.ChangeListener;
    import javafx.beans.value.ObservableValue;
    import javafx.event.ActionEvent;
    import javafx.event.EventHandler;
    import javafx.geometry.Insets;
    import javafx.scene.Scene;
    import javafx.scene.control.Button;
    import javafx.scene.effect.PerspectiveTransform;
    import javafx.scene.layout.StackPane;
    import javafx.stage.Stage;
    import javafx.util.Duration;
    
    /**
     * 
     * @author ggrec
     *
     */
    public class DFXFlipPaneTester extends Application
    {
    
        // ==================== 1. Static Fields ========================
    
        /*
         * Mmm... pie.
         */
        private static final Double PIE = Math.PI;
    
        private static final Double HALF_PIE = Math.PI / 2;
    
        private static final double ANIMATION_DURATION = 10000;
    
        private static final double ANIMATION_RATE = 10;
    
    
        // ====================== 2. Instance Fields =============================
    
        private Timeline animation;
    
        private StackPane flipPane;
    
        private SimpleDoubleProperty angle = new SimpleDoubleProperty(HALF_PIE);
    
        private PerspectiveTransform transform = new PerspectiveTransform();
    
        private SimpleBooleanProperty flippedProperty = new SimpleBooleanProperty(true);
    
    
        // ==================== 3. Static Methods ====================
    
        public static void main(final String[] args)
        {
            Application.launch(args);
        }
    
    
        // ==================== 5. Creators ====================
    
        @Override
        public void start(final Stage primaryStage) throws Exception
        {
            primaryStage.setScene(new Scene(createFlipPane()));
            primaryStage.show();
        }
    
        private StackPane createFlipPane()
        {
            angle = createAngleProperty();
    
            flipPane = new StackPane();
            flipPane.setPadding(new Insets(30));
    
            flipPane.setMinHeight(500);
            flipPane.setMinWidth(500);
    
            flipPane.getChildren().setAll(createBackNode(), createFrontNode());
    
            flipPane.widthProperty().addListener(new ChangeListener<Number>() {
    
                @Override public void changed(final ObservableValue<? extends Number> arg0, final Number arg1, final Number arg2)
                {
                    recalculateTransformation(angle.doubleValue());
                }
            });
    
            flipPane.heightProperty().addListener(new ChangeListener<Number>() {
    
                @Override public void changed(final ObservableValue<? extends Number> arg0, final Number arg1, final Number arg2)
                {
                    recalculateTransformation(angle.doubleValue());
                }
            });
    
            return flipPane;
        }
    
        private StackPane createFrontNode()
        {
            final StackPane node = new StackPane();
    
            node.setEffect(transform);
            node.visibleProperty().bind(flippedProperty);
    
            node.getChildren().setAll(createButton("Front Button")); //$NON-NLS-1$
    
            return node;
        }
    
        private StackPane createBackNode()
        {
            final StackPane node = new StackPane();
    
            node.setEffect(transform);
            node.visibleProperty().bind(flippedProperty.not());
    
            node.getChildren().setAll(createButton("Back Button")); //$NON-NLS-1$
    
            return node;
        }
    
        private Button createButton(final String text)
        {
            final Button button = new Button(text);
            button.setMaxHeight(Double.MAX_VALUE);
            button.setMaxWidth(Double.MAX_VALUE);
    
            button.setOnAction(new EventHandler<ActionEvent>() {
    
                @Override public void handle(final ActionEvent arg0)
                {
                    flip();
                }
            });
    
            return button;
        }
    
        private SimpleDoubleProperty createAngleProperty()
        {
            // --------------------- <Angle> -----------------------
    
            final SimpleDoubleProperty angle = new SimpleDoubleProperty(HALF_PIE);
    
            angle.addListener(new ChangeListener<Number>() {
    
                @Override public void changed(final ObservableValue<? extends Number> obsValue, final Number oldValue, final Number newValue)
                {
                    recalculateTransformation(newValue.doubleValue());
                }
            });
    
            return angle;
        }
    
        private Timeline createAnimation()
        {
            return new Timeline(
    
                    new KeyFrame(Duration.millis(0),    new KeyValue(angle, HALF_PIE)),
    
                    new KeyFrame(Duration.millis(ANIMATION_DURATION / 2),  new KeyValue(angle, 0, Interpolator.EASE_IN)),
    
                    new KeyFrame(Duration.millis(ANIMATION_DURATION / 2),  new EventHandler<ActionEvent>() {
    
                        @Override public void handle(final ActionEvent arg0)
                        {
                            // TODO -- Do they another way or API to do this?
                            flippedProperty.set( flippedProperty.not().get() );
                        }
                    }),
    
                    new KeyFrame(Duration.millis(ANIMATION_DURATION / 2),  new KeyValue(angle, PIE)),
    
                    new KeyFrame(Duration.millis(ANIMATION_DURATION), new KeyValue(angle, HALF_PIE, Interpolator.EASE_OUT))
    
                    );
        }
    
    
        // ==================== 6. Action Methods ====================
    
        private void flip()
        {
            if (animation == null)
                animation = createAnimation();
    
            animation.setRate( flippedProperty.get() ? ANIMATION_RATE : -ANIMATION_RATE );
    
            animation.play();
        }
    
    
        // ==================== 8. Business Methods ====================
    
        private void recalculateTransformation(final double angle)
        {
            final double insetsTop = flipPane.getInsets().getTop() * 2;
            final double insetsLeft = flipPane.getInsets().getLeft() * 2;
    
            final double radius = flipPane.widthProperty().subtract(insetsLeft).divide(2).doubleValue();
            final double height = flipPane.heightProperty().subtract(insetsTop).doubleValue();
            final double back = height / 10;
    
            /*
             * Compute transform.
             * 
             * Don't bother understanding these unless you're a math passionate.
             * 
             * You may Google "Affine Transformation - Rotation"
             */
            transform.setUlx(radius - Math.sin(angle) * radius);
            transform.setUly(0 - Math.cos(angle) * back);
            transform.setUrx(radius + Math.sin(angle) * radius);
            transform.setUry(0 + Math.cos(angle) * back);
            transform.setLrx(radius + Math.sin(angle) * radius);
            transform.setLry(height - Math.cos(angle) * back);
            transform.setLlx(radius - Math.sin(angle) * radius);
            transform.setLly(height + Math.cos(angle) * back);
        }
    
    }
    

    关于具有 PerspectiveTransform 的 JavaFX 翻转节点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22360258/

    相关文章:

    java - 如何访问内存池 mbean

    java - 未定义的 getTabHost() 方法

    java - 如何在 map 中的 map 中迭代 map

    JavaFX BarChart xAxis 标签错误定位

    JavaFX - 使用 mediaplayer 和 mediaview 播放视频

    security - JRE 1.7 漏洞

    JavaFX FXML-SceneBuilder-图像可调整大小

    java - 在 JavaFX 中切换主题

    java - 限制 JavaFX TextField 的字符数导致撤消时出现 IndexOutOfBounds

    java - javafx 中使用 TableView 进行多重过滤