JavaFX 缩放转换

JavaFX ScaleTransition

大家好,我正在尝试向我的游戏中添加卡片翻转动画,但我遇到了一些我不理解的异常,而且我没有一直得到它们,有时它们会停止转换。enter image description here 这是我的转换代码。

public void transitionAnimation(ImageView imageView,Image image){
    ScaleTransition front = new ScaleTransition(Duration.seconds(0.15),imageView);
    ScaleTransition back = new ScaleTransition(Duration.seconds(0.15),imageView);

    front.setFromX(1);
    front.setToX(0);
    front.setCycleCount(1);
    front.play();

    back.setFromX(0);
    back.setToX(1);
    back.setCycleCount(1);
    back.setDelay(Duration.seconds(0.15));
    back.play();

    Timer timer = new Timer();
    TimerTask timerTask = new TimerTask() {
        @Override
        public void run() {
            imageView.setImage(image);
            timer.cancel();
            timer.purge();
        }
    };
    timer.schedule(timerTask,148);
}
Exception in thread "JavaFX Application Thread" java.lang.IndexOutOfBoundsException: Index -1 out of bounds for length 180
    at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
    at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
    at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:248)
    at java.base/java.util.Objects.checkIndex(Objects.java:359)
    at java.base/java.util.ArrayList.get(ArrayList.java:427)
    at javafx.graphics/javafx.scene.Parent.updateCachedBounds(Parent.java:1701)
    at javafx.graphics/javafx.scene.Parent.recomputeBounds(Parent.java:1645)
    at javafx.graphics/javafx.scene.Parent.doComputeGeomBounds(Parent.java:1498)
    at javafx.graphics/javafx.scene.Parent.access0(Parent.java:79)
    at javafx.graphics/javafx.scene.Parent.doComputeGeomBounds(Parent.java:115)
    at javafx.graphics/com.sun.javafx.scene.ParentHelper.computeGeomBoundsImpl(ParentHelper.java:84)
    at javafx.graphics/com.sun.javafx.scene.layout.RegionHelper.superComputeGeomBoundsImpl(RegionHelper.java:78)
    at javafx.graphics/com.sun.javafx.scene.layout.RegionHelper.superComputeGeomBounds(RegionHelper.java:62)
    at javafx.graphics/javafx.scene.layout.Region.doComputeGeomBounds(Region.java:3289)
    at javafx.graphics/javafx.scene.layout.Region.access0(Region.java:147)
    at javafx.graphics/javafx.scene.layout.Region.doComputeGeomBounds(Region.java:168)
    at javafx.graphics/com.sun.javafx.scene.layout.RegionHelper.computeGeomBoundsImpl(RegionHelper.java:89)
    at javafx.graphics/com.sun.javafx.scene.NodeHelper.computeGeomBounds(NodeHelper.java:115)
    at javafx.graphics/javafx.scene.Node.updateGeomBounds(Node.java:3837)
    at javafx.graphics/javafx.scene.Node.getGeomBounds(Node.java:3799)
    at javafx.graphics/javafx.scene.Node.getLocalBounds(Node.java:3747)
    at javafx.graphics/javafx.scene.Node.updateTxBounds(Node.java:3901)
    at javafx.graphics/javafx.scene.Node.getTransformedBounds(Node.java:3693)
    at javafx.graphics/javafx.scene.Parent.getChildTransformedBounds(Parent.java:1845)
    at javafx.graphics/javafx.scene.Parent.recomputeBounds(Parent.java:1634)
    at javafx.graphics/javafx.scene.Parent.doComputeGeomBounds(Parent.java:1498)
    at javafx.graphics/javafx.scene.Parent.access0(Parent.java:79)
    at javafx.graphics/javafx.scene.Parent.doComputeGeomBounds(Parent.java:115)
    at javafx.graphics/com.sun.javafx.scene.ParentHelper.computeGeomBoundsImpl(ParentHelper.java:84)
    at javafx.graphics/com.sun.javafx.scene.layout.RegionHelper.superComputeGeomBoundsImpl(RegionHelper.java:78)
    at javafx.graphics/com.sun.javafx.scene.layout.RegionHelper.superComputeGeomBounds(RegionHelper.java:62)
    at javafx.graphics/javafx.scene.layout.Region.doComputeGeomBounds(Region.java:3289)
    at javafx.graphics/javafx.scene.layout.Region.access0(Region.java:147)
    at javafx.graphics/javafx.scene.layout.Region.doComputeGeomBounds(Region.java:168)
    at javafx.graphics/com.sun.javafx.scene.layout.RegionHelper.computeGeomBoundsImpl(RegionHelper.java:89)
    at javafx.graphics/com.sun.javafx.scene.NodeHelper.computeGeomBounds(NodeHelper.java:115)
    at javafx.graphics/javafx.scene.Node.updateGeomBounds(Node.java:3837)
    at javafx.graphics/javafx.scene.Node.getGeomBounds(Node.java:3799)
    at javafx.graphics/javafx.scene.Node.getLocalBounds(Node.java:3747)
    at javafx.graphics/javafx.scene.Node.intersectsBounds(Node.java:5282)
    at javafx.graphics/javafx.scene.Node.intersectsBounds(Node.java:548)
    at javafx.graphics/com.sun.javafx.scene.NodeHelper.intersectsBounds(NodeHelper.java:262)
    at javafx.graphics/javafx.scene.layout.Region.doPickNodeLocal(Region.java:3158)
    at javafx.graphics/javafx.scene.layout.Region.access0(Region.java:147)
    at javafx.graphics/javafx.scene.layout.Region.doPickNodeLocal(Region.java:184)
    at javafx.graphics/com.sun.javafx.scene.layout.RegionHelper.pickNodeLocalImpl(RegionHelper.java:104)
    at javafx.graphics/com.sun.javafx.scene.NodeHelper.pickNodeLocal(NodeHelper.java:128)
    at javafx.graphics/javafx.scene.Node.pickNode(Node.java:5192)
    at javafx.graphics/javafx.scene.Scene$MouseHandler.pickNode(Scene.java:3993)
    at javafx.graphics/javafx.scene.Scene$MouseHandler.access00(Scene.java:3579)
    at javafx.graphics/javafx.scene.Scene.pick(Scene.java:2029)
    at javafx.graphics/javafx.scene.Scene.access00(Scene.java:172)
    at javafx.graphics/javafx.scene.Scene$MouseHandler.process(Scene.java:3805)
    at javafx.graphics/javafx.scene.Scene$MouseHandler.access00(Scene.java:3579)
    at javafx.graphics/javafx.scene.Scene.processMouseEvent(Scene.java:1849)
    at javafx.graphics/javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2588)
    at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:397)
    at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:295)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
    at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent(GlassViewEventHandler.java:434)
    at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:390)
    at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:433)
    at javafx.graphics/com.sun.glass.ui.View.handleMouseEvent(View.java:556)
    at javafx.graphics/com.sun.glass.ui.View.notifyMouse(View.java:942)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop(WinApplication.java:174)
    at java.base/java.lang.Thread.run(Thread.java:832)

Process finished with exit code 0

您的 TimerTask 在后台线程上运行,并从该线程更新 ImageView。由于 JavaFX 与大多数 UI 工具包一样是单线程的,因此这里的行为是不确定的;您正在看到跨多个线程的数据不一致的影响。

只需使用动画 API 专门管理这样的功能;例如使用 SequentialTransition:

public void transitionAnimation(ImageView imageView,Image image){
    ScaleTransition front = new ScaleTransition(Duration.seconds(0.15),imageView);
    ScaleTransition back = new ScaleTransition(Duration.seconds(0.15),imageView);

    front.setFromX(1);
    front.setToX(0);
    front.setCycleCount(1);

    front.setOnFinished(e -> imageView.setImage(image));

    back.setFromX(0);
    back.setToX(1);
    back.setCycleCount(1);

    new SequentialTransition(front, back).play();

}

Timeline:

public void transitionAnimation(ImageView imageView,Image image){

    KeyFrame start = new KeyFrame(Duration.ZERO, new KeyValue(imageView.scaleXProperty(), 1.0));
    KeyFrame middle = new KeyFrame(
        Duration.millis(150),
        e -> imageView.setImage(image),
        new KeyValue(imageView.scaleXProperty(), 0.0)
    );
    KeyFrame end = new KeyFrame(Duration.millis(300), new KeyValue(imageView.scaleXProperty(), 1.0));
    new Timeline(start, middle, end).play();
}