第 7 課:創建動畫對象
JavaFX 庫提供了對創建動畫的內置支持。本課向您展示如何構建圖形對象並使用線性插值爲其設置動畫(JavaFX 庫支持的一種關鍵幀動畫)。本課中的示例使用 JavaFX Script 語言的聲明性語法以及數據綁定、圖形和特定於節點的功能,因此可能有助於您熟悉學習 JavaFX Script 編程語言、在圖形場景中顯示 UI 對象和創建圖形對象。 |
- | 創建應用程序窗口 |
- | 創建圖形場景 |
- | 添加背景圖像 |
- | 繪製一片雲 |
- | 創建水平運動 |
- | 控制時間線週期 |
- | 添加垂直運動 |
本課介紹向簡單應用程序添加動畫的逐步操作過程。考慮創建一片雲,在晴空中飄浮,碰到窗口邊界時反彈,如以下窗口所示。
要評估和測試您的動畫應用程序,請創建一個擴展名爲 .fx
的文件,例如 cloud.fx
。
您可以在任意時間使用以下命令編譯您的代碼:
javafxc cloud.fx |
您可以使用以下命令運行編譯的代碼:
javafx cloud |
使用 Stage
類創建一個窗口:
- 爲
javafx.stage.Stage
類添加import
語句。 - 將
Stage
對象字面值添加到代碼中。
正如您在在圖形場景中顯示 UI 對象中所瞭解到的那樣,UI 組件、形狀、文本和圖像被當作是圖形場景中的對象分層結構。這些圖形對象的動畫也在場景中進行,因此下一步是創建一個場景。
- 爲
Scene
和Color
類添加import
語句。 - 將
Scene
對象字面值添加到Stage
類的scene
實例變量中。 - 使用
Scene
類的fill
變量定義場景的顏色。import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
Stage{
title: "Cloud"
visible: true
scene:
Scene{
fill: Color.WHITE
}//Scene
}//Stage
有關 JavaFX Script 編程語言中採用的聲明性語法的更多信息,請參閱“使用聲明性語法”。
在 JavaFX SDK 中,圖像是使用 javafx.scene.image.Image
類創建的,圖像位置在 url
實例變量中指定。請注意,只能將一個 Node
對象添加到場景內容中,因此,您需要使用一個名爲 ImageView
的適配器類。有關場景和節點的更多詳細信息,請參見在圖形場景中顯示 UI 對象。
- 爲
Image
和ImageView
類添加兩個新的導入。 - 設置一個圖像,用作飄浮的雲的背景。您可以使用位於 java.sun.com 中的日照圖像:
/javafx/1/tutorials/ui/animation/weather-sun.png
這些更改將反映在修改後的代碼中,如下所示:
import javafx.stage.Stage; |
編譯和運行之後,此修改後的代碼將生成以下窗口。
注意:由於沒有指定窗口的寬度和高度,因此圖像剛好填滿窗口。
通過繪製 5 個首尾相接的弧來創建實際的雲。第一個弧的終點是第二個弧的起點。下圖對此進行了說明。
要在代碼中繪製此雲,您需要執行以下步驟:
- 使用
javafx.scene.shape
軟件包中的MoveTo
、ArcTo
和Path
類,如以下代碼片段所示。Path {
fill: Color.WHITE
stroke: Color.LIGHTBLUE
strokeWidth: 2
effect: Lighting{light: DistantLight{azimuth: 90}}
elements: [
MoveTo { x: 15 y: 15 },
ArcTo { x: 50 y: 10 radiusX: 20 radiusY: 20 sweepFlag: true},
ArcTo { x: 70 y: 20 radiusX: 20 radiusY: 20 sweepFlag: true},
ArcTo { x: 50 y: 60 radiusX: 20 radiusY: 20 sweepFlag: true},
ArcTo { x: 20 y: 50 radiusX: 10 radiusY: 5 sweepFlag: true},
ArcTo { x: 15 y: 15 radiusX: 10 radiusY: 10 sweepFlag: true},
]
}//PathMoveTo
類用於指示此形狀的起點,ArcTo
類用於創建弧段。使用Path
類(表示一個簡單的形狀)將所有弧段組合成一個形狀,然後啓用基本的幾何路徑構造。如果需要創建一個自己的形狀,使其不同於javafx.scene.shape
軟件包中提供的基本圖形形狀,則Path
類很有用。Path
類擴展了Node
類,並繼承了後者的所有實例變量和函數。
注意:sweepFlag
實例變量已設置爲true
,因此按順時針方向(“正”角度)繪製弧。如果按逆時針方向繪製弧,這些弧將不能正確彎曲。 - 應用以下代碼創建照明效果,使雲具有浮雕感。
effect: Lighting{light: DistantLight{azimuth: 90}}
這種效果模擬使用一個遠距光源照亮對象。azimuth
實例變量用於定義光源的角度。 - 爲
MoveTo
、ArcTo
、Path
、Lighting
和DistantLight
類添加import
語句。
有關形狀和視覺效果的更多信息,請參閱創建圖形對象。以下修改後的代碼包含圖形場景、圖像和雲:import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.shape.ArcTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.effect.Lighting;
import javafx.scene.effect.light.DistantLight;
Stage{
title: "Cloud"
visible: true
scene:
Scene{
fill: Color.WHITE
content:[
ImageView{image:
Image{url: "/docs/books/tutorial/2d/basic2d/examples/images/weather-sun.png"}
},
Path {
fill: Color.WHITE
stroke: Color.LIGHTBLUE
strokeWidth: 2
effect: Lighting{light: DistantLight{azimuth: 90}}
elements: [
MoveTo { x: 15 y: 15 },
ArcTo { x: 50 y: 10 radiusX: 20 radiusY: 20 sweepFlag: true},
ArcTo { x: 70 y: 20 radiusX: 20 radiusY: 20 sweepFlag: true},
ArcTo { x: 50 y: 60 radiusX: 20 radiusY: 20 sweepFlag: true},
ArcTo { x: 20 y: 50 radiusX: 10 radiusY: 5 sweepFlag: true},
ArcTo { x: 15 y: 15 radiusX: 10 radiusY: 10 sweepFlag: true},
]
}//Path
]
}//Scene
}//Stage
編譯和運行之後,此修改後的代碼將生成以下窗口。圖 4:具有一個圖像和一個看上去像雲的形狀的窗口
下一步是爲雲設置動畫。JavaFX Script 語言支持關鍵幀動畫概念。這意味着,圖形場景的動畫狀態過渡是通過場景在某些時間點的狀態的起始快照和結束快照(關鍵幀)聲明的。給定這兩個狀態後,系統就可以自動執行動畫。一經請求,它就可以停止、暫停、繼續、反向或重複運動。
首先,通過設置雲的水平動畫(沒有垂直運動)來簡化任務。然後,再添加垂直運動。要設置雲的水平動畫,請更改 Path
對象的 translateX
實例變量,並保持 translateY
實例變量不變。請執行以下步驟:
- 將
Path
對象的translateY
變量設置爲 15。 - 爲起始點 (0, 15) 和結束點 (387, 15) 定義關鍵幀。要計算這些值,請考慮圖像大小 (470x119) 和形狀大小 (83x64)。下圖說明了這些尺寸。圖 5:關鍵幀
動畫沿着由javafx.animation.Timeline
對象表示的時間線進行。每條時間線包含由javafx.animation.KeyFrame
對象表示的兩個或多個關鍵幀。 - 創建具有兩個關鍵幀的時間線來執行雲的水平運動,並在啓動應用程序時開始此運動。起始點和結束點之間的位置是使用線性插值計算的。
import javafx.animation.Timeline;
import javafx.animation.KeyFrame;
import javafx.animation.Interpolator;
var x: Number;
Timeline {
keyFrames: [
KeyFrame{
time: 0s
values: x => 0.0
},
KeyFrame{
time: 7s
values: x => 387.0 tween Interpolator.LINEAR
}
]
}.play();time
實例變量用來定義所經過的時間,在這段時間裏,將在單個Timeline
對象週期內設置關聯值。time
是javafx.lang.Duration
類的變量,它具有一個Number
值,後跟 "s" 或 "ms"(分別表示秒和毫秒)。=>
運算符爲關鍵值列表提供了一個字面值構造函數。tween
運算符是插值的字面值構造函數。因此,在 7 秒鐘內,雲從像素 0 開始移到位置 387。
儘管KeyFrame
動畫是典型的 JavaFX 對象,但 JavaFX 提供了一種特殊的語法,與標準的對象字面值語法相比,使用這種語法表示動畫更簡單。使用 trigger 子句可將任意回調與關鍵幀相關聯。由at
指定的時間是相對於時間線的起點的。此功能可簡化代碼,如下所示:import javafx.animation.Timeline;
import javafx.animation.KeyFrame;
import javafx.animation.Interpolator;
var x: Number;
Timeline {
keyFrames: [
at (0s) {x => 0.0},
at (7s) {x => 387.0 tween Interpolator.LINEAR}
]
}.play(); - 將
Path
對象的translateX
實例變量綁定到x
變量,如以下代碼片段所示:Path{
...
translateX: bind x
...
}
在x
變量發生變化時,Path
對象的translateX
對象也隨之發生變化。有關數據綁定機制的更多詳細信息,請參見對 UI 對象應用數據綁定。
您可以使用 Timeline
類的實例變量來控制時間線週期。
- 將
repeatCount
實例變量設置爲Timeline.INDEFINITE
可以循環動畫。 - 將
autoReverse
實例變量設置爲true
可以啓用雙向運動。
以下代碼可完成這些任務:
import javafx.animation.Timeline; |
此應用程序修改後的代碼如下所示:
import javafx.animation.Interpolator; |
編譯和運行之後,此代碼將生成以下窗口:
此動畫應用程序使用可按均勻時間增量移動對象的線性插值。您可以嘗試其他形式的插值。例如,如果您設置 Interpolator.EASEBOTH
類型,則在時間線週期的起點和終點,雲的運動速度將稍微下降。
您可以通過創建最初所需的飄浮效果來改進應用程序。
- 爲此形狀的
y
座標創建另一個時間線。 - 將
translateY
實例變量綁定到y
值,如以下代碼片段所示:var y: Number;
Timeline {
repeatCount: Timeline.INDEFINITE
autoReverse: true
keyFrames: [
at (0s) {y => 0.0},
at (4s) {y => 55.0 tween Interpolator.LINEAR},
]
}.play();
...
Path{
...
translateY: bind y
...
}//Path
注意:在四秒鐘之後,y
變量達到其最大值位置,這比x
變量要快。因此,translateY
值變化得比translateX
快。這將產生漫遊效果。
以下是此示例的完整代碼。import javafx.animation.Interpolator;
import javafx.animation.Timeline;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.shape.ArcTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.effect.Lighting;
import javafx.scene.effect.light.DistantLight;
var x: Number;
Timeline {
repeatCount: Timeline.INDEFINITE
autoReverse: true
keyFrames: [
at (0s) {x => 0.0},
at (7s) {x => 387.0 tween Interpolator.LINEAR},
]
}.play();
var y: Number;
Timeline {
repeatCount: Timeline.INDEFINITE
autoReverse: true
keyFrames: [
at (0s) {y => 0.0},
at (4s) {y => 55.0 tween Interpolator.LINEAR},
]
}.play();
Stage{
title: "Cloud"
visible: true
scene:
Scene{
fill: Color.WHITE
content:[
ImageView{image:
Image{url: "/docs/books/tutorial/2d/basic2d/examples/images/weather-sun.png"}
},
Path {
translateX: bind x
translateY: bind y
fill: Color.WHITE
stroke: Color.LIGHTBLUE
strokeWidth: 2
effect: Lighting{light: DistantLight{azimuth: 90}}
elements: [
MoveTo { x: 15 y: 15 },
ArcTo { x: 50 y: 10 radiusX: 20 radiusY: 20 sweepFlag: true},
ArcTo { x: 70 y: 20 radiusX: 20 radiusY: 20 sweepFlag: true},
ArcTo { x: 50 y: 60 radiusX: 20 radiusY: 20 sweepFlag: true},
ArcTo { x: 20 y: 50 radiusX: 10 radiusY: 5 sweepFlag: true},
ArcTo { x: 15 y: 15 radiusX: 10 radiusY: 10 sweepFlag: true},
]
}//Path
]
}//Scene
onClose: function() {
java.lang.System.exit(0);
}//close action
}//Stage
編譯和運行之後,此代碼將生成以下窗口。圖 7:在窗口內反彈的雲
本課介紹瞭如何創建動畫對象,並對插值動畫進行了分析。請嘗試使用本課中提到的概念和技巧來探究 JavaFX SDK 的其他動畫功能。