0

I found this top answer (first block of code) that helped me rotate an image (a card in my case). But how do I attach a back cover (example) to that rotating card?

Community
  • 1
  • 1
Alex
  • 839
  • 1
  • 12
  • 24

2 Answers2

1

Assuming you didn't change the camera and the angles where you don't see the image at all are still 90° and 270°, you can just swap the Image in the ImageView at those angles as well change the scaleX property at those angles to -1 and 1 respectively so that you do not need to mirror the original image.

The following code is a modified version of jewelsea's answer to "Flip a card animation", so credit for parts of the code has to be given to that user.

public class QuickFlip extends Application {
    @Override
    public void start(Stage stage) throws Exception {
        BooleanProperty showFront = new SimpleBooleanProperty(true);

        Node card = createCard(showFront,
                new Image("http://www.ohmz.net/wp-content/uploads/2012/05/Game-of-Throne-Magic-trading-cards-2.jpg"),
                new Image("https://upload.wikimedia.org/wikipedia/en/a/aa/Magic_the_gathering-card_back.jpg")
                );

        stage.setScene(createScene(card));
        stage.show();

        // first 90° -> show front
        RotateTransition rotator1 = createRotator(card, 0, 90);

        // from 90° to 270° show backside
        rotator1.setOnFinished(evt -> showFront.set(false));
        RotateTransition rotator2 = createRotator(card, 90, 270);

        // from 270° to 360° show front again
        rotator2.setOnFinished(evt -> showFront.set(true));
        RotateTransition rotator3 = createRotator(card, 270, 360);

        SequentialTransition rotator = new SequentialTransition(card, rotator1, rotator2, rotator3);
        rotator.setCycleCount(10);
        rotator.play();
    }

    private Scene createScene(Node card) {
        StackPane root = new StackPane();
        root.getChildren().addAll(card);

        Scene scene = new Scene(root, 600, 700, true, SceneAntialiasing.BALANCED);
        scene.setCamera(new PerspectiveCamera());

        return scene;
    }

    private Node createCard(BooleanProperty showFront, Image front, Image back) {
        ImageView imageView = new ImageView();

        imageView.setFitHeight(front.getHeight());
        imageView.setFitWidth(front.getWidth());

        // show front/back depending on value of the showFront property
        imageView.imageProperty().bind(Bindings.when(showFront).then(front).otherwise(back));

        // mirror image, when backside is shown to prevent wrong orientation
        imageView.scaleXProperty().bind(Bindings.when(showFront).then(1d).otherwise(-1d));
        return imageView;
    }

    private RotateTransition createRotator(Node card, double fromAngle, double toAngle) {
        // animation length proportional to the rotation angle
        RotateTransition rotator = new RotateTransition(Duration.millis(Math.abs(10000 * (fromAngle - toAngle) / 360)), card);
        rotator.setAxis(Rotate.Y_AXIS);
        rotator.setFromAngle(fromAngle);
        rotator.setToAngle(toAngle);
        rotator.setInterpolator(Interpolator.LINEAR);

        return rotator;
    }

    public static void main(String[] args) {
        launch();
    }
}
Community
  • 1
  • 1
fabian
  • 80,457
  • 12
  • 86
  • 114
1

You can make the rotation transition occur in parallel with a discrete Timeline that switches the image at the times when the card flips. In the case of the original QuickFlip demo, those times are 2500 and 7500 milliseconds:

import javafx.animation.*;
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.image.*;
import javafx.scene.layout.StackPane;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;
import javafx.util.Duration;

public class QuickFlip2 extends Application {
    @Override
    public void start(Stage stage) throws Exception {
        ImageView card = new ImageView();

        stage.setScene(createScene(card));
        stage.show();

        Animation rotator = createRotator(card);
        rotator.play();
    }

    private Scene createScene(Node card) {
        StackPane root = new StackPane();
        root.getChildren().add(card);

        Scene scene = new Scene(root, 600, 700, true, SceneAntialiasing.BALANCED);
        scene.setCamera(new PerspectiveCamera());

        return scene;
    }

    private Animation createRotator(ImageView card) {
        RotateTransition rotator = new RotateTransition(Duration.millis(10000), card);
        rotator.setAxis(Rotate.Y_AXIS);
        rotator.setFromAngle(0);
        rotator.setToAngle(360);
        rotator.setInterpolator(Interpolator.LINEAR);
        rotator.setCycleCount(10);

        Image front = new Image(
            "http://www.ohmz.net/wp-content/uploads/2012/05/Game-of-Throne-Magic-trading-cards-2.jpg",
            false);
        Image back = new Image(
            "https://upload.wikimedia.org/wikipedia/commons/thumb/3/30/Card_back_05a.svg/329px-Card_back_05a.svg.png",
            front.getWidth(), front.getHeight(), true, true);

        Timeline imageSwitcher = new Timeline(
            new KeyFrame(Duration.ZERO,
                new KeyValue(card.imageProperty(), front, Interpolator.DISCRETE)),
            new KeyFrame(Duration.millis(2500),
                new KeyValue(card.imageProperty(), back, Interpolator.DISCRETE)),
            new KeyFrame(Duration.millis(7500),
                new KeyValue(card.imageProperty(), front, Interpolator.DISCRETE)),
            new KeyFrame(Duration.millis(10000),
                new KeyValue(card.imageProperty(), front, Interpolator.DISCRETE))
        );
        imageSwitcher.setCycleCount(10);

        return new ParallelTransition(card, rotator, imageSwitcher);
    }

    public static void main(String[] args) {
        launch();
    }
}
VGR
  • 40,506
  • 4
  • 48
  • 63