Reputation: 3145
After reading through the documentation, I'm still a bit confused on how to execute an animation after another one has completed. I have a timeline like so:
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)
}
}
This runs them all at once, but I would like to run each animation after the other one has finished! I can't quite figure out how to do this.. (sorry if this is obvious, I am very new to Kotlin and Java in general!)
I see that the keyframe has an onFinished
property but I can't quite figure out what I'm supposed to actually set it to. Is there a better way to do this? Thank you!
Upvotes: 4
Views: 672
Reputation: 4786
In this case where you're just setting scales and rotations, there are some nice helpers already in the library. This should work for you:
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()
The play = false
everywhere is required since these helpers were designed for simple one-off auto-playing animations.
Edit
After a discussion in Slack, these may be simplified in a future release, so the above may eventually be as easy as
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()
Watch the release notes for more info!
Another Edit
Looks like I was over complicating things a bit. You can just use this if you like it more:
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()
Upvotes: 1
Reputation: 233
There's a JavaFX class "SequentialTransition" that will run your timelines in sequence. You'll need to disable the TornadoFX autoplay with a flag passed into the timeline builder. Check out ParallelTransition if you want to run these all at once using a similar coding pattern.
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)
}
}
}
Upvotes: 3
Reputation: 7297
Based on the structure proposed by @tornadofx-fan I've added builders for sequentialTransition and parallelTransition, so starting from TornadoFX 1.7.9 you can do the same like this:
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)
}
}
}
The timeline builder inside of these transitions don't automatically play, while the transition itself automatically plays when the builder is completed. You can pass play=false
to the transition builder to disable autoplay.
Also note the usage of 0.5.seconds
to generate the Duration objects :)
Upvotes: 4