Последовательная анимация в 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, но я не могу понять, что я должен на самом деле установить. Есть лучший способ сделать это? Спасибо!


person shan    schedule 21.07.2017    source источник


Ответы (3)


Есть класс JavaFX «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)
        }
    }

}
person Wall0p    schedule 21.07.2017
comment
работал как шарм, спасибо! Мне нравится формат использования .then, очень читаемый и простой для понимания для такого новичка, как я, лол - person shan; 28.07.2017

На основе структуры, предложенной @ tornadofx-fan, я добавил построители для sequenceTransition и 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 :)

person Edvin Syse    schedule 21.07.2017
comment
обалденно, рад за 1.7.9! : ^) - person shan; 28.07.2017

В этом случае, когда вы просто устанавливаете масштаб и поворот, в библиотеке уже есть несколько хороших помощников. Это должно сработать для вас:

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 повсюду, поскольку эти помощники были разработаны для простых одноразовых анимаций с автоматическим воспроизведением.

Изменить

После обсуждения в 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()
person Ruckus T-Boom    schedule 21.07.2017