3 アニメーションの基本
JavaFXでのアニメーションは、タイムライン・アニメーションと遷移に分けられます。この章では、各アニメーション・タイプの例を示します。
Timeline
およびTransition
は、javafx.animation.Animation
クラスのサブクラスです。特定のクラス、メソッドまたは追加機能の詳細は、APIドキュメントを参照してください。
遷移
JavaFXでの遷移には、内部タイムラインにアニメーションを組み込む手段が用意されています。遷移を構成することにより、パラレルに、または順次実行される複数のアニメーションを作成できます。詳細は、「パラレル遷移」および「順次遷移」を参照してください。次の各項では、遷移アニメーションの例を示します。
フェード遷移
フェード遷移では、一定時間にわたってノードの不透明度を変更します。
例3-1に、四角形に適用されるフェード遷移のコード・スニペットを示します。最初に角丸四角形が作成されてから、フェード遷移が適用されます。
例3-1 フェード遷移
final Rectangle rect1 = new Rectangle(10, 10, 100, 100); rect1.setArcHeight(20); rect1.setArcWidth(20); rect1.setFill(Color.RED); ... FadeTransition ft = new FadeTransition(Duration.millis(3000), rect1); ft.setFromValue(1.0); ft.setToValue(0.1); ft.setCycleCount(Timeline.INDEFINITE); ft.setAutoReverse(true); ft.play();
パス遷移
パス遷移では、一定時間にわたってノードがパスの一方の端から反対側の端まで移動します。
例3-2に、四角形に適用されるパス遷移のコード・スニペットを示します。四角形がパスの終端に達すると、アニメーションは逆方向に動きます。コード内では、最初に角丸四角形が作成されてから、新しいパス・アニメーションが作成され、四角形に適用されます。
例3-2 パス遷移
final Rectangle rectPath = new Rectangle (0, 0, 40, 40); rectPath.setArcHeight(10); rectPath.setArcWidth(10); rectPath.setFill(Color.ORANGE); ... Path path = new Path(); path.getElements().add(new MoveTo(20,20)); path.getElements().add(new CubicCurveTo(380, 0, 380, 120, 200, 120)); path.getElements().add(new CubicCurveTo(0, 120, 0, 240, 380, 240)); PathTransition pathTransition = new PathTransition(); pathTransition.setDuration(Duration.millis(4000)); pathTransition.setPath(path); pathTransition.setNode(rectPath); pathTransition.setOrientation(PathTransition.OrientationType.ORTHOGONAL_TO_TANGENT); pathTransition.setCycleCount(Timeline.INDEFINITE); pathTransition.setAutoReverse(true); pathTransition.play();
パラレル遷移
パラレル遷移では、複数の遷移が同時に実行されます。
例3-3に、四角形に適用されるフェード、平行移動、回転およびスケーリング遷移を実行するパラレル遷移のコード・スニペットを示します。
例3-3 パラレル遷移
Rectangle rectParallel = new Rectangle(10,200,50, 50); rectParallel.setArcHeight(15); rectParallel.setArcWidth(15); rectParallel.setFill(Color.DARKBLUE); rectParallel.setTranslateX(50); rectParallel.setTranslateY(75); ... FadeTransition fadeTransition = new FadeTransition(Duration.millis(3000), rectParallel); fadeTransition.setFromValue(1.0f); fadeTransition.setToValue(0.3f); fadeTransition.setCycleCount(2); fadeTransition.setAutoReverse(true); TranslateTransition translateTransition = new TranslateTransition(Duration.millis(2000), rectParallel); translateTransition.setFromX(50); translateTransition.setToX(350); translateTransition.setCycleCount(2); translateTransition.setAutoReverse(true); RotateTransition rotateTransition = new RotateTransition(Duration.millis(3000), rectParallel); rotateTransition.setByAngle(180f); rotateTransition.setCycleCount(4); rotateTransition.setAutoReverse(true); ScaleTransition scaleTransition = new ScaleTransition(Duration.millis(2000), rectParallel); scaleTransition.setToX(2f); scaleTransition.setToY(2f); scaleTransition.setCycleCount(2); scaleTransition.setAutoReverse(true); parallelTransition = new ParallelTransition(); parallelTransition.getChildren().addAll( fadeTransition, translateTransition, rotateTransition, scaleTransition ); parallelTransition.setCycleCount(Timeline.INDEFINITE); parallelTransition.play();
順次遷移
順次遷移では、複数の遷移を順番に実行します。
例3-4に、順番に実行される順次遷移のコードを示します。四角形に適用されるフェード、平行移動、回転およびスケーリング遷移です。
例3-4 順次遷移
Rectangle rectSeq = new Rectangle(25,25,50,50); rectSeq.setArcHeight(15); rectSeq.setArcWidth(15); rectSeq.setFill(Color.CRIMSON); rectSeq.setTranslateX(50); rectSeq.setTranslateY(50); ... FadeTransition fadeTransition = new FadeTransition(Duration.millis(1000), rectSeq); fadeTransition.setFromValue(1.0f); fadeTransition.setToValue(0.3f); fadeTransition.setCycleCount(1); fadeTransition.setAutoReverse(true); TranslateTransition translateTransition = new TranslateTransition(Duration.millis(2000), rectSeq); translateTransition.setFromX(50); translateTransition.setToX(375); translateTransition.setCycleCount(1); translateTransition.setAutoReverse(true); RotateTransition rotateTransition = new RotateTransition(Duration.millis(2000), rectSeq); rotateTransition.setByAngle(180f); rotateTransition.setCycleCount(4); rotateTransition.setAutoReverse(true); ScaleTransition scaleTransition = new ScaleTransition(Duration.millis(2000), rectSeq); scaleTransition.setFromX(1); scaleTransition.setFromY(1); scaleTransition.setToX(2); scaleTransition.setToY(2); scaleTransition.setCycleCount(1); scaleTransition.setAutoReverse(true); sequentialTransition = new SequentialTransition(); sequentialTransition.getChildren().addAll( fadeTransition, translateTransition, rotateTransition, scaleTransition); sequentialTransition.setCycleCount(Timeline.INDEFINITE); sequentialTransition.setAutoReverse(true); sequentialTransition.play();
アニメーションおよび遷移の詳細は、SDKのEnsembleプロジェクト内のAPIドキュメントおよびアニメーションに関する項を参照してください。
タイムライン・アニメーション
アニメーションは、サイズ、場所および色などの関連するプロパティによって動きます。Timeline
には、時間の推移に応じてプロパティ値を更新する機能があります。JavaFXは、キー・フレーム・アニメーションをサポートしています。キー・フレーム・アニメーションでは、アニメーション化されたグラフィカル・シーンの状態遷移は、特定の時間におけるシーン状態の開始および終了スナップショット(キー・フレーム)によって宣言されます。アニメーションは自動的に実行できます。リクエストされた時点における動きの停止、一時停止、再開、逆戻りまたは繰返しが可能です。
基本タイムライン・アニメーション
例3-5のコードでは、四角形を横方向にアニメーション化し、元の位置であるX=100
からX=300
へ500ミリ秒で移動しています。オブジェクトを横方向にアニメーション化するには、x座標を変更し、y座標はそのままにします。
例3-5に、基本タイムライン・アニメーションのコード・スニペットを示します。
例3-5 タイムライン・アニメーション
final Rectangle rectBasicTimeline = new Rectangle(100, 50, 100, 50); rectBasicTimeline.setFill(Color.RED); ... final Timeline timeline = new Timeline(); timeline.setCycleCount(Timeline.INDEFINITE); timeline.setAutoReverse(true); final KeyValue kv = new KeyValue(rectBasicTimeline.xProperty(), 300); final KeyFrame kf = new KeyFrame(Duration.millis(500), kv); timeline.getKeyFrames().add(kf); timeline.play();
タイムライン・イベント
JavaFXには、タイムラインの再生中にトリガーできるイベントを組み込む手段が用意されています。例3-6のコードにより、指定した範囲内の円の半径が変更され、KeyFrame
により、シーンのx座標内の円のランダムな遷移がトリガーされます。
例3-6 タイムライン・イベント
import javafx.application.Application; import javafx.stage.Stage; import javafx.animation.AnimationTimer; import javafx.animation.KeyFrame; import javafx.animation.KeyValue; import javafx.animation.Timeline; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.effect.Lighting; import javafx.scene.layout.StackPane; import javafx.scene.paint.Color; import javafx.scene.shape.Circle; import javafx.scene.text.Text; import javafx.util.Duration; public class TimelineEvents extends Application { //main timeline private Timeline timeline; private AnimationTimer timer; //variable for storing actual frame private Integer i=0; @Override public void start(Stage stage) { Group p = new Group(); Scene scene = new Scene(p); stage.setScene(scene); stage.setWidth(500); stage.setHeight(500); p.setTranslateX(80); p.setTranslateY(80); //create a circle with effect final Circle circle = new Circle(20, Color.rgb(156,216,255)); circle.setEffect(new Lighting()); //create a text inside a circle final Text text = new Text (i.toString()); text.setStroke(Color.BLACK); //create a layout for circle with text inside final StackPane stack = new StackPane(); stack.getChildren().addAll(circle, text); stack.setLayoutX(30); stack.setLayoutY(30); p.getChildren().add(stack); stage.show(); //create a timeline for moving the circle timeline = new Timeline(); timeline.setCycleCount(Timeline.INDEFINITE); timeline.setAutoReverse(true); //You can add a specific action when each frame is started. timer = new AnimationTimer() { @Override public void handle(long l) { text.setText(i.toString()); i++; } }; //create a keyValue with factory: scaling the circle 2times KeyValue keyValueX = new KeyValue(stack.scaleXProperty(), 2); KeyValue keyValueY = new KeyValue(stack.scaleYProperty(), 2); //create a keyFrame, the keyValue is reached at time 2s Duration duration = Duration.millis(2000); //one can add a specific action when the keyframe is reached EventHandler onFinished = new EventHandler<ActionEvent>() { public void handle(ActionEvent t) { stack.setTranslateX(java.lang.Math.random()*200-100); //reset counter i = 0; } }; KeyFrame keyFrame = new KeyFrame(duration, onFinished , keyValueX, keyValueY); //add the keyframe to the timeline timeline.getKeyFrames().add(keyFrame); timeline.play(); timer.start(); } public static void main(String[] args) { Application.launch(args); } }
補間
補間では、動きの開始ポイントと終了ポイント間のオブジェクトの位置を定義します。補間クラスの様々な組込み実装を使用することも、独自の補間を実装して補間のカスタム動作を実現することもできます。
組込み補間
JavaFXには、アニメーションで様々な効果を作成するために使用できる組込み補間が複数用意されています。デフォルトでは、JavaFXでは、線形補間を使用して座標を計算します。
例3-7に、基本タイムライン・アニメーション内のKeyValueにEASE_BOTH補間インスタンスを追加するコード・スニペットを示します。この補間により、オブジェクトが開始ポイントおよび終了ポイントに達した際にばね効果を作成します。
例3-7 組込み補間
final Rectangle rectBasicTimeline = new Rectangle(100, 50, 100, 50); rectBasicTimeline.setFill(Color.BROWN); ... final Timeline timeline = new Timeline(); timeline.setCycleCount(Timeline.INDEFINITE); timeline.setAutoReverse(true); final KeyValue kv = new KeyValue(rectBasicTimeline.xProperty(), 300, Interpolator.EASE_BOTH); final KeyFrame kf = new KeyFrame(Duration.millis(500), kv); timeline.getKeyFrames().add(kf); timeline.play();
カスタム補間
組込み補間とは別に、独自の補間を実装して補間のカスタム動作を実現できます。カスタム補間の例は、2つのJavaファイルで構成されています。例3-8に、アニメーションのy座標を計算するために使用されるカスタム補間を示します。例3-9に、AnimationBooleanInterpolatorが使用されるアニメーションのコード・スニペットを示します。