ループアニメーション
このエントリーはJavaFX Advent Calendarの25日目です。
12月15日に開催されたJJUG CCCでStream APIについて登壇しました。その内容はさておき、そのプレゼン資料で使用したアニメーションについて紹介しておきます。
知っている人には当たり前化もしれないですけど。
このプレゼンではStreamということで、流れるものをモチーフにした絵や写真、音楽などを使用しました。タイトルやセクションのタイトルで使用したアニメーションもそう。ベルトコンベアで文字が流れてくるという感じにしています。
このスクリーンショットは文字が切れてしまっているのではなくて、流れている途中なのです。
このアニメーションなんですが、実をいうととても簡単に作ってます。
原理的には短いアニメーションをループさせているだけ。
まず、簡単なサンプルで示しましょう。
package net.javainthebox.loopanim; import java.util.stream.IntStream; import javafx.animation.Animation; import javafx.animation.Interpolator; import javafx.animation.TranslateTransition; import javafx.application.Application; import javafx.scene.Group; import javafx.scene.Node; import javafx.scene.Scene; import javafx.scene.layout.Pane; import javafx.scene.paint.Color; import javafx.scene.shape.Rectangle; import javafx.stage.Stage; import javafx.util.Duration; public class LoopAnimation extends Application { @Override public void start(Stage stage) throws Exception { Pane root = new Pane(); init(root); Scene scene = new Scene(root, 400, 100); stage.setScene(scene); stage.show(); } void init(Pane pane) { Rectangle rectangle = new Rectangle(0.0, 50.0, 40.0, 10.0); rectangle.setFill(Color.WHITE); rectangle.setStroke(Color.BLACK); pane.getChildren().add(rectangle); startAnimation(rectangle); } void startAnimation(Node node) { TranslateTransition trans = new TranslateTransition(Duration.millis(1_000), node); trans.setToX(40.0); trans.setInterpolator(Interpolator.LINEAR); trans.setCycleCount(Animation.INDEFINITE); trans.play(); } public static void main(String... args) { launch(args); } }
このサンプルを実行すると、長方形が移動を繰り返すというアニメーションを実行します。
この長方形は40ピクセルだけ横方向に移動しています。肝となるのは長方形の幅も40ピクセルだということ。
長方形を描画しているのが、initメソッドです。長方形を生成している部分を抜き出しました。
Rectangle rectangle = new Rectangle(0.0, 50.0, 40.0, 10.0);
第1, 2引数が長方形の左上の座標。第3引数が幅で、第4引数が高さです。
これに対し、アニメーションしているのが、startAnimationメソッドです。抜粋したのが、以下。
void startAnimation(Node node) { TranslateTransition trans = new TranslateTransition(Duration.millis(1_000), node); trans.setToX(40.0); trans.setInterpolator(Interpolator.LINEAR); trans.setCycleCount(Animation.INDEFINITE); trans.play(); }
移動のアニメーションを行うのが、TranslateTransitionクラスです。コンストラクタの第1引数がアニメーションの長さ、第2引数がアニメーションを行うターゲットです。
第1引数で1秒を指定しているので、1秒のサイクルで繰り返しを行っています。
そのあとの、setToXメソッドが移動した後のX座標を示しています。0から移動しているので、40ピクセルでちょうど長方形の幅と一緒になっています。
次のsetInterpolatorメソッドははじめゆっくり、中は急いで、最後はまたゆっくりなどのように、アニメーションの動きの見た目のスムーズさなどを指定します。ただ、ここでははじめゆっくりとかやっていると、ぎこちなくなるので、常に同じ速さでアニメーションするLINEARを指定しています。
setCycleCountメソッドはアニメーションの繰り返し回数を指定しますが、ここでは無限ループにしています。
最後にplayメソッドでアニメーションの開始です。
これで、長方形が繰り返し移動するアニメーションができます。
長方形1つだけなら意味ないと思いますよね。そうです、この長方形を並べてあげれば、ベルトコンベアのベルト的なものになるわけです。
移動する時に左側が欠けてしまわないように、画面の外側の部分から用意しておきます。ということで、initメソッドを以下のように変更しました。
void init(Pane pane) { Group group = new Group(); IntStream.range(0, 11) .forEach(i -> { Rectangle rectangle = new Rectangle(40.0*i - 40.0, 50.0, 40.0, 10.0); rectangle.setFill(Color.WHITE); rectangle.setStroke(Color.BLACK); group.getChildren().add(rectangle); }); pane.getChildren().add(group); startAnimation(group); }
複数の長方形をGroupオブジェクトでまとめています。
このGroupオブジェクトをアニメーションすれば、あら不思議、永遠にベルトコンベアが動いているように見えます。
http://f.hatena.ne.jp/skrb/20181225223729
スクリーンショットなので、動きがよく分からないとは思いますが、ぜひサンプルを試してみてください!
同じ原理を使えば、歯車とか、エスカレータなどのアニメーションもできるはず。実際にCCCのプレゼンでは歯車も一緒に回転させています。
ということで、ループアニメーションの紹介でした。