使用PerspectiveTransform的JavaFX Flip节点

时间:2014-03-12 18:10:59

标签: java javafx javafx-2 flip

JavaFX 2.x

我想做什么:

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

    我不想做的事情:

  • 使用RotateTransition因为它取决于PerspectiveCamera。由于我会将许多可翻转的瓷砖彼此相邻,因此动画中途的前/后替换效果不会很好。

    到目前为止我所拥有的:

    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();
            }
        }
    
    }
    
  • 2 个答案:

    答案 0 :(得分:7)

    经过繁重的研发后,我设法实现了翻转功能,而不是 PerspectiveCamera,只使用 PerspectiveTransform。< / p>

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

    问:但乔治,这与其他方法有什么不同?
    A:嗯,首先:由于您未使用PerspectiveCamera,如果您说有100个翻转图块,则用户的观点不会受到影响屏幕。倒数第二个:后节点已被翻转。所以它没有镜像,它没有旋转,它没有缩放。它正常&#34;。 Ain那么棒?

    干杯。


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

    答案 1 :(得分:2)

    Oracle创建了一个名为DisplayShelf的示例。它类似于您链接的PhotoFlip应用程序,但是是为Java 2+实现的。 Oracle示例代码位于Ensemble Sample Application中。您可以在JavaFX open source repository

    中查看DisplayShelf源代码

    display shelf

    DisplayShelf是Cover Flow动画的PerspectiveTransform样式实现,因此它与完整图像翻转不完全相同。但是许多原则是相同的,所以你应该能够研究DisplayShelf示例,然后开发出符合你需求的代码。

    JavaFX的相关图像翻转问题=&gt; Flip a card animation