TornadoFX 中的连续动画?

Consecutive animation in TornadoFX?

通读文档后,我仍然对如何在另一个动画完成后执行动画感到困惑。我有这样的时间表:

timeline {
  keyframe(Duration.seconds(0.5)) {
    keyvalue(firstImg.scaleXProperty(), 1.0, interpolator = Interpolator.EASE_BOTH)
    keyvalue(firstImg.scaleYProperty(), 1.0, interpolator = Interpolator.EASE_BOTH)
    keyvalue(firstImg.rotateProperty(), 0.0, interpolator = Interpolator.EASE_BOTH)
  }

  keyframe(Duration.seconds(0.5)) {
    keyvalue(secondImg.scaleXProperty(), 1.0, interpolator = Interpolator.EASE_BOTH)
    keyvalue(secondImg.scaleYProperty(), 1.0, interpolator = Interpolator.EASE_BOTH)
    keyvalue(secondImg.rotateProperty(), 0.0, interpolator = Interpolator.EASE_BOTH)
  }

  keyframe(Duration.seconds(0.5)) {
    keyvalue(thirdImg.scaleXProperty(), 1.0, interpolator = Interpolator.EASE_BOTH)
    keyvalue(thirdImg.scaleYProperty(), 1.0, interpolator = Interpolator.EASE_BOTH)
    keyvalue(thirdImg.rotateProperty(), 0.0, interpolator = Interpolator.EASE_BOTH)
  }

  keyframe(Duration.seconds(0.5)) {
    keyvalue(fourthImg.scaleXProperty(), 1.0, interpolator = Interpolator.EASE_BOTH)
    keyvalue(fourthImg.scaleYProperty(), 1.0, interpolator = Interpolator.EASE_BOTH)
    keyvalue(fourthImg.rotateProperty(), 0.0, interpolator = Interpolator.EASE_BOTH)
  }
}

这 运行 一次完成所有动画,但我想 运行 每个动画都在另一个动画完成后播放!我不太明白该怎么做..(抱歉,如果这很明显,我对 Kotlin 很陌生,一般来说 Java!

我看到关键帧有一个 onFinished 属性,但我不太明白我应该 将其设置为 .有一个更好的方法吗?谢谢!

有一个 JavaFX class "SequentialTransition" 将 运行 按顺序排列您的时间线。您需要使用传递给时间线构建器的标志来禁用 TornadoFX 自动播放。如果您想使用类似的编码模式一次性 运行 这些,请查看 ParallelTransition。

class STTest : View("My View") {

    val r1 = Rectangle(20.0, 20.0, Color.RED)
    val r2 = Rectangle(20.0, 20.0, Color.YELLOW)
    val r3 = Rectangle(20.0, 20.0, Color.GREEN)
    val r4 = Rectangle(20.0, 20.0, Color.BLUE)

    override val root = vbox {

        button("Animate") {
            setOnAction {

                val t1 = timeline(false) {
                    keyframe(Duration.seconds(0.5)) {
                        keyvalue(r1.translateXProperty(), 50.0, interpolator = Interpolator.EASE_BOTH)
                    }
                }
                val t2 = timeline(false) {
                    keyframe(Duration.seconds(0.5)) {
                        keyvalue(r2.translateXProperty(), 100.0, interpolator = Interpolator.EASE_BOTH)
                    }
                }
                val t3 = timeline(false) {
                    keyframe(Duration.seconds(0.5)) {
                        keyvalue(r3.translateXProperty(), 150.0, interpolator = Interpolator.EASE_BOTH)
                    }
                }
                val t4 = timeline(false) {
                    keyframe(Duration.seconds(0.5)) {
                        keyvalue(r4.translateXProperty(), 200.0, interpolator = Interpolator.EASE_BOTH)
                    }
                }

                /* functions look better
                val st = SequentialTransition()
                st.children += t1
                st.children += t2
                st.children += t3
                st.children += t4

                st.play()
                */  

                t1.then(t2).then(t3).then(t4).play()

            }
        }
        pane {
            add(r1)
            add(r2)
            add(r3)
            add(r4)
        }
    }

}

基于@tornadofx-fan 提出的结构,我添加了 sequentialTransition 和 parallelTransition 的构建器,因此从 TornadoFX 1.7.9 开始,您可以这样做:

class TransitionViews: View() {
   val r1 = Rectangle(20.0, 20.0, Color.RED)
   val r2 = Rectangle(20.0, 20.0, Color.YELLOW)
   val r3 = Rectangle(20.0, 20.0, Color.GREEN)
   val r4 = Rectangle(20.0, 20.0, Color.BLUE)

   override val root = vbox {
       button("Animate").action {
           sequentialTransition {
               timeline {
                   keyframe(0.5.seconds) {
                       keyvalue(r1.translateXProperty(), 50.0, interpolator = Interpolator.EASE_BOTH)
                   }
               }
               timeline {
                   keyframe(0.5.seconds) {
                       keyvalue(r2.translateXProperty(), 100.0, interpolator = Interpolator.EASE_BOTH)
                   }
               }
               timeline {
                   keyframe(0.5.seconds) {
                       keyvalue(r3.translateXProperty(), 150.0, interpolator = Interpolator.EASE_BOTH)
                   }
               }
               timeline {
                   keyframe(0.5.seconds) {
                       keyvalue(r4.translateXProperty(), 200.0, interpolator = Interpolator.EASE_BOTH)
                   }
               }
           }
       }
       pane {
           add(r1)
           add(r2)
           add(r3)
           add(r4)
       }
   }
}

这些转场中的时间轴构建器不会自动播放,而转场本身会在构建器完成后自动播放。您可以将 play=false 传递给转换构建器以禁用自动播放。

还要注意 0.5.seconds 生成 Duration 对象的用法:)

在这种情况下,您只是设置比例和旋转,库中已有一些不错的帮手。这应该适合你:

val time = 0.5.seconds
firstImg.scale(time, Point2D(1.0, 1.0), play = false).and(firstImg.rotate(time, 0.0, play = false))
        .then(secondImg.scale(time, Point2D(1.0, 1.0), play = false).and(secondImg.rotate(time, 0.0, play = false)))
        .then(thirdImg.scale(time, Point2D(1.0, 1.0), play = false).and(thirdImg.rotate(time, 0.0, play = false)))
        .then(fourthImg.scale(time, Point2D(1.0, 1.0), play = false).and(fourthImg.rotate(time, 0.0, play = false)))
        .play()

play = false 到处都是必需的,因为这些助手是为简单的一次性自动播放动画而设计的。

编辑

a discussion in Slack之后,这些可能会在未来的版本中得到简化,所以上面的最终可能会像

一样简单
val time = 0.5.seconds
listOf(
    firstImg.scale(time, 1 p 1) and firstImg.rotate(time, 0),
    secondImg.scale(time, 1 p 1) and secondImg.rotate(time, 0),
    thirdImg.scale(time, 1 p 1) and thirdImg.rotate(time, 0),
    fourthImg.scale(time, 1 p 1) and fourthImg.rotate(time, 0)
).playSequential()

查看发行说明了解更多信息!

另一个编辑

看来我把事情复杂化了一点。如果您更喜欢它,可以直接使用它:

val time = 0.5.seconds
SequentialTransition(
    firstImg.scale(time, Point2D(1.0, 1.0), play = false).and(firstImg.rotate(time, 0.0, play = false)).
    secondImg.scale(time, Point2D(1.0, 1.0), play = false).and(secondImg.rotate(time, 0.0, play = false)),
    thirdImg.scale(time, Point2D(1.0, 1.0), play = false).and(thirdImg.rotate(time, 0.0, play = false)),
    fourthImg.scale(time, Point2D(1.0, 1.0), play = false).and(fourthImg.rotate(time, 0.0, play = false))
).play()