JavaFX 动画简介

此页面由 Connor SchweighöferUPL 下贡献

The javafx.animation 包提供了一个简单的框架,用于在 JavaFX 应用程序中创建动画和过渡。它基于 WritableValue<T> 的原理,该原理在 JavaFX 中被广泛使用。WritableValue<T> 是一个接口,它封装了一个可以读取和设置的值。它通常用于存储 JavaFX UI 元素中的属性,例如 Rectangle 形状中的 widthheight。它还提供各种内置过渡以实现常见效果,支持并行和顺序过渡,以及在动画完成时处理事件的能力。

本文介绍了所有类型的动画,从 Animation 及其子类 TransitionTimeline 开始,然后使用 AnimationTimer 表示更低级的动画。虽然 Transition 提供了一种更简单、更用户友好的创建动画的方式,但 Timeline 提供了更大的灵活性,适用于更复杂的动画。相比之下,AnimationTimer 专为逐帧更新而设计,不使用 WritableValue<T>

动画

抽象类 Animation 提供了 TransitionTimeline 动画的核心功能,不能直接扩展。

一个 Animation 包含多个属性

  • targetFramerate 是此 Animation 运行的最大帧速率(每秒帧数)。
  • currentTimeAnimation 中的当前时间点,以 Duration 表示。
  • rate 定义了 Animation 预期播放的方向和速度。它支持正数和负数。
  • cycleCount 定义了此 Animation 的循环次数。它在运行时不能更改,并且必须为正数。
  • cycleDuration 是此 Animation 一个循环的 Duration。它是 Animation 从开始到结束播放所需的时间,以默认速率 1.0 播放
  • totalDuration 指示此 Animation 的总持续时间,包括重复。它是 cycleDuration * cycleCountDuration.INDEFINITE 的结果。
  • delayAnimation 开始时的延迟 Duration
  • autoReverse 属性指定 Animation 是否将在交替循环中以反向播放。
  • onFinished 事件处理程序用于定义 Animation 完成时的附加行为。
  • status 表示 Animation 的当前状态,可能的状态包括 PAUSEDRUNNINGSTOPPED

此外,它还提供了一些有用的方法,例如 play()playFrom(String cuePoint)pause()stop() 等,用于控制动画流程。快速浏览 其文档 可以很好地概述其功能。

过渡

The Transition 抽象类是所有过渡的基础类,它提供了一种常见的 Animation 形式。JavaFX 为常见的 NodeShape 属性提供了各种内置过渡。

淡入淡出过渡

The FadeTransition 创建淡入淡出效果。这是通过定期更新 Nodeopacity 属性来实现的。

FadeTransition

Circle circle = new Circle(150, 150, 20, Color.GREEN);

FadeTransition transition = new FadeTransition(Duration.seconds(5), circle);
transition.setFromValue(1.0);
transition.setToValue(0);
transition.setInterpolator(Interpolator.LINEAR);

transition.play();

(有关设置 JavaFX 应用程序的完整指南,请参阅本文:JavaFX 应用程序基本结构示例)

填充过渡

The FillTransition 创建一个动画,该动画会更改形状的填充。这是通过定期更新 Shapefill 属性来实现的。

FillTransition

Circle circle = new Circle(150, 150, 20, Color.GREEN);

FillTransition transition = new FillTransition(Duration.seconds(5), circle);
transition.setFromValue(Color.GREEN);
transition.setToValue(Color.BLACK);
transition.setInterpolator(Interpolator.LINEAR);

transition.play();

平移过渡

The TranslateTransition 创建一个从一个位置到另一个位置的直线移动/平移动画。这是通过定期更新 NodetranslateXtranslateYtranslateZ 属性来实现的。

TranslateTransition

Circle circle = new Circle(50, 50, 10, Color.GREEN);

TranslateTransition transition = new TranslateTransition(Duration.seconds(5), circle);
transition.setToX(200);
transition.setToY(200);
transition.setInterpolator(Interpolator.LINEAR);

transition.play();

路径过渡

The PathTransition 创建一个使用由一系列形状指定的复杂预定义路径的移动动画。沿着路径的平移是通过定期更新 NodetranslateXtranslateY 属性来实现的,如果 orientation 设置为 OrientationType.ORTHOGONAL_TO_TANGENT,则 rotate 变量也会得到更新。

PathTransition

Circle circle = new Circle(50, 50, 10, Color.GREEN);

Path path = new Path();
path.getElements().add(new MoveTo(50, 50)); // starting point
path.getElements().add(new LineTo(250, 250));

PathTransition transition = new PathTransition(Duration.seconds(5), path, circle);
transition.setInterpolator(Interpolator.LINEAR);

transition.play();

旋转过渡

The RotateTransition 创建一个旋转动画。这是通过定期更新 Noderotate 属性来实现的。角度值以度为单位指定。

RotateTransition

Rectangle rectangle = new Rectangle(125, 125, 50, 50);
rectangle.setFill(Color.GREEN);

RotateTransition transition = new RotateTransition(Duration.seconds(5), rectangle);
transition.setFromAngle(0);
transition.setToAngle(360);
transition.setInterpolator(Interpolator.LINEAR);

transition.play();

缩放过渡

The ScaleTransition 创建一个缩放动画,该动画会更改节点的大小。这是通过定期更新 NodescaleXscaleYscaleZ 属性来实现的。

ScaleTransition

Circle circle = new Circle(150, 150, 50, Color.GREEN);

ScaleTransition transition = new ScaleTransition(Duration.seconds(5), circle);
transition.setToX(0.1);
transition.setToY(0.1);
transition.setInterpolator(Interpolator.LINEAR);

transition.play();

描边过渡

The StrokeTransition 创建一个动画,该动画会更改形状的描边颜色。这是通过定期更新 Shapestroke 属性来实现的。

StrokeTransition

Circle circle = new Circle(150, 150, 50, Color.GREEN);
circle.setStrokeWidth(5);

StrokeTransition transition = new StrokeTransition(Duration.seconds(5), circle);
transition.setFromValue(Color.GREEN);
transition.setToValue(Color.BLACK);
transition.setInterpolator(Interpolator.LINEAR);

transition.play();

顺序过渡

The SequentialTransition 按顺序播放一系列动画。不建议包含一个 Animation,该 Animation 不是最后一个具有 Duration.INDEFINITEAnimation,因为这将阻止序列中的所有后续动画。

暂停过渡

The PauseTransition 为指定的 duration 创建一个暂停。此行为对于在 SequentialTransition 中创建延迟很有用,在 SequentialTransition 中没有属性更改。

PauseTransition

Circle circle = new Circle(150, 150, 20, Color.GREEN);
circle.setStrokeWidth(5);

ScaleTransition smaller = new ScaleTransition(Duration.seconds(1.5));
smaller.setToX(0.25);
smaller.setToY(0.25);
smaller.setInterpolator(Interpolator.LINEAR);

ScaleTransition larger = new ScaleTransition(Duration.seconds(1.5));
larger.setToX(1);
larger.setToY(1);
larger.setInterpolator(Interpolator.LINEAR);

SequentialTransition transition = new SequentialTransition(
        circle,
        smaller,
        new PauseTransition(Duration.seconds(2)),
        larger
);
transition.play();

请注意,此代码仅在 SequentialTransition 上设置一个 Node,它是此处的父过渡,而不是在各个子过渡上设置。它们将隐式使用其父过渡的 Node

并行过渡

The ParallelTransition 并行播放一组动画。

ParallelTransition

Rectangle rectangle = new Rectangle(50, 50, 10, 10);
rectangle.setFill(Color.GREEN);

TranslateTransition translate = new TranslateTransition(Duration.seconds(5));
translate.setToX(200);
translate.setToY(200);
translate.setInterpolator(Interpolator.LINEAR);

RotateTransition rotate = new RotateTransition(Duration.seconds(5));
rotate.setFromAngle(0);
rotate.setToAngle(360);
rotate.setInterpolator(Interpolator.LINEAR);

ParallelTransition transition = new ParallelTransition(rectangle, translate, rotate);
transition.play();

时间轴

A Timeline 用于在任何 WritableValue<T> 上定义自由形式的 Animation。如果没有任何内置过渡在所需的属性上运行,它将很有用。它由一系列顺序的 KeyFrame 组成,每个 KeyFrame 都封装了时间中的一个时刻。它们共同指定了目标属性在整个持续时间内的演变方式。

警告:正在从 FX 运行时引用正在运行的 Timeline。在无限时间轴中,具有动画属性的对象将不会被垃圾回收,这可能会导致内存泄漏。因此,请确保在不再需要时间轴实例时停止它。

关键帧

A KeyFrame 表示动画序列中的特定时刻(提示点),并包含一组 KeyValue 实例,这些实例在给定的 Duration 内发生变化。一个 KeyFrame 可以有一个名称,然后可以使用该名称在动画中识别此 KeyFrame,例如,使用 playFrom(String cuePoint) 从此特定 KeyFrame 开始。还可以提供 onFinished 实现,该实现将在命中此提示点时被调用。

关键值

A KeyValueWritableValue<T> 和类型为 T 的目标值之间建立映射。这用于定义值的更改。还可以额外定义一个 Interpolator 来设置此值的更改速率。KeyValue 类是不可变的。

示例

Timeline 示例创建一个 Circle,它在 5 秒的持续时间内在 x 方向上移动 200 像素

TimelineExample

Circle circle = new Circle(50, 150, 10, Color.GREEN);

KeyValue x = new KeyValue(circle.translateXProperty(), 200);
KeyFrame frame = new KeyFrame(Duration.seconds(5), x);
Timeline timeline = new Timeline(frame);

timeline.play();

插值器

The Interpolator 抽象类定义了值随时间变化的速率,影响动画的平滑度。有几种内置实现用于常见的插值技术。

注意:默认情况下,所有过渡(ParallelTransitionSequentialTransition 除外)都使用 Interpolator#EASE_BOTH

以下是使用 Timeline 中的示例对 Interpolator 进行可视化的示例

离散

The Interpolator.DISCRETE 插值器在值之间创建突然的过渡,没有任何中间步骤。

Discrete

Circle circle = new Circle(50, 150, 10, Color.GREEN);

KeyValue x = new KeyValue(circle.translateXProperty(), 200, Interpolator.DISCRETE);
KeyFrame frame = new KeyFrame(Duration.seconds(5), x);
Timeline timeline = new Timeline(frame);

timeline.play();

线性

The Interpolator.LINEAR 插值器在时间内产生值之间的恒定变化速率。

Linear

缓入

Interpolator.EASE_IN 插值器 从缓慢开始,随着动画的进行逐渐加速。

EaseIn

缓出

Interpolator.EASE_OUT 插值器 从快速开始,随着动画的进行逐渐减速。

EaseOut

缓进缓出

Interpolator.EASE_BOTH 插值器 从缓慢开始,在中间加速,然后在结束时减速。它结合了 EASE_INEASE_OUT 的特性。

EaseBoth

此外,还有两个用于 Interpolator.SPLINEInterpolator.TANGENT 插值的静态工厂方法。

动画计时器

AnimationTimer 抽象类 提供了创建动画的最低级别选项。handle(long now) 方法在动画处于活动状态时在每一帧中被调用。时间戳 now 是当前帧的时间(以纳秒为单位),对于在该帧中调用的所有 AnimationTimer 来说都是相同的。此外,AnimationTimer 还添加了 start()stop() 方法来处理动画的生命周期。

注意:handle 方法将在 JavaFX 应用程序线程 中调用,因此应避免长时间运行和阻塞操作。为了保持每秒 30 帧的流畅帧速率,整个 JavaFX 应用程序理想情况下每帧分配不超过 33 毫秒。

结论

在本教程中,您已经探索了 javafx.animation 包,并学习了如何在 JavaFX 应用程序中创建动态动画。我们首先了解了基础的 Animation 类,然后继续学习 TransitionTimeline 类,它们提供了创建和控制动画的不同方法。此外,您还学习了如何通过几个 Interpolator 示例来控制动画的进度。最后,我们介绍了 AnimationTimer 类,它允许进行精确的逐帧更新动画。有了这些工具,您现在就可以在 JavaFX 应用程序中创建丰富的动画了。

上次更新: 2024 年 5 月 31 日


返回教程列表