JavaFX 动画简介

JavaFX 动画简介

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

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

动画

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

一个 Animation 包含多个属性

targetFramerate 是此 Animation 运行的最大帧速率(每秒帧数)。

currentTime 是 Animation 中的当前时间点,以 Duration 表示。

rate 定义了 Animation 预期播放的方向和速度。它支持正数和负数。

cycleCount 定义了此 Animation 的循环次数。它在运行时不能更改,并且必须为正数。

cycleDuration 是此 Animation 一个循环的 Duration。它是 Animation 从开始到结束播放所需的时间,以默认速率 1.0 播放。

totalDuration 指示此 Animation 的总持续时间,包括重复。它是 cycleDuration * cycleCount 或 Duration.INDEFINITE 的结果。

delay 是 Animation 开始时的延迟 Duration。

autoReverse 属性指定 Animation 是否将在交替循环中以反向播放。

onFinished 事件处理程序用于定义 Animation 完成时的附加行为。

status 表示 Animation 的当前状态,可能的状态包括 PAUSED、RUNNING 和 STOPPED。

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

过渡

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

淡入淡出过渡

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

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 创建一个动画,该动画会更改形状的填充。这是通过定期更新 Shape 的 fill 属性来实现的。

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 创建一个从一个位置到另一个位置的直线移动/平移动画。这是通过定期更新 Node 的 translateX、translateY 和 translateZ 属性来实现的。

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 创建一个使用由一系列形状指定的复杂预定义路径的移动动画。沿着路径的平移是通过定期更新 Node 的 translateX 和 translateY 属性来实现的,如果 orientation 设置为 OrientationType.ORTHOGONAL_TO_TANGENT,则 rotate 变量也会得到更新。

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 创建一个旋转动画。这是通过定期更新 Node 的 rotate 属性来实现的。角度值以度为单位指定。

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 创建一个缩放动画,该动画会更改节点的大小。这是通过定期更新 Node 的 scaleX、scaleY 和 scaleZ 属性来实现的。

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 创建一个动画,该动画会更改形状的描边颜色。这是通过定期更新 Shape 的 stroke 属性来实现的。

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.INDEFINITE 的 Animation,因为这将阻止序列中的所有后续动画。

暂停过渡

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

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 并行播放一组动画。

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

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

关键帧

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

关键值

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

示例

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

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 抽象类定义了值随时间变化的速率,影响动画的平滑度。有几种内置实现用于常见的插值技术。

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

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

离散

The Interpolator.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 插值器在时间内产生值之间的恒定变化速率。

缓入

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

缓出

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

缓进缓出

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

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

动画计时器

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

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

结论

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

相关推荐

黑户征信不好从什么地方可以贷款?10个征信黑可以贷款的app
匣的组词
365登录次数限制

匣的组词

📅 06-30 👁️ 8247
耳机从初入门到中高级的15个真相问答与评价
365登录次数限制

耳机从初入门到中高级的15个真相问答与评价

📅 06-30 👁️ 1713
FGO贞德和黑贞德综合能力实战点评
365bet直播

FGO贞德和黑贞德综合能力实战点评

📅 06-27 👁️ 6154
让应用设置再丰富一点:App Settings
365现在还能安全提款吗

让应用设置再丰富一点:App Settings

📅 06-29 👁️ 5411
保卫萝卜3:高效攻略,轻松刷取小吉技巧大揭秘
365现在还能安全提款吗

保卫萝卜3:高效攻略,轻松刷取小吉技巧大揭秘

📅 06-27 👁️ 9224
认识世界过程中的“锤子”陷阱
365现在还能安全提款吗

认识世界过程中的“锤子”陷阱

📅 06-30 👁️ 1168
法国十大著名建筑 法国标志性建筑物盘点 法国地标建筑有哪些→MAIGOO生活榜
路由器怎么防止偷网,怎么防止路由器被入侵
365现在还能安全提款吗

路由器怎么防止偷网,怎么防止路由器被入侵

📅 06-28 👁️ 6707