第 7 課:創建動畫對象

 第 7 課:創建動畫對象

JavaFX 庫提供了對創建動畫的內置支持。本課向您展示如何構建圖形對象並使用線性插值爲其設置動畫(JavaFX 庫支持的一種關鍵幀動畫)。本課中的示例使用 JavaFX Script 語言的聲明性語法以及數據綁定、圖形和特定於節點的功能,因此可能有助於您熟悉學習 JavaFX Script 編程語言在圖形場景中顯示 UI 對象創建圖形對象
 
目錄


創建應用程序窗口
創建圖形場景
添加背景圖像
繪製一片雲
創建水平運動
控制時間線週期
添加垂直運動
 

本課介紹向簡單應用程序添加動畫的逐步操作過程。考慮創建一片雲,在晴空中飄浮,碰到窗口邊界時反彈,如以下窗口所示。

 
在窗口內反彈的雲
圖 1:在窗口內反彈的雲
 


要評估和測試您的動畫應用程序,請創建一個擴展名爲 .fx 的文件,例如 cloud.fx

您可以在任意時間使用以下命令編譯您的代碼:

javafxc cloud.fx


您可以使用以下命令運行編譯的代碼:

javafx cloud


使用 Stage 類創建一個窗口:

  1. javafx.stage.Stage 類添加 import 語句。
  2. Stage 對象字面值添加到代碼中。

正如您在在圖形場景中顯示 UI 對象中所瞭解到的那樣,UI 組件、形狀、文本和圖像被當作是圖形場景中的對象分層結構。這些圖形對象的動畫也在場景中進行,因此下一步是創建一個場景。

  1. SceneColor 類添加 import 語句。
  2. Scene 對象字面值添加到 Stage類的 scene 實例變量中。
  3. 使用 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 對象

  1. ImageImageView 類添加兩個新的導入。
  2. 設置一個圖像,用作飄浮的雲的背景。您可以使用位於 java.sun.com 中的日照圖像:/javafx/1/tutorials/ui/animation/weather-sun.png

這些更改將反映在修改後的代碼中,如下所示:

import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
Stage{
title: "Cloud"
visible: true
scene:
Scene{
fill: Color.WHITE
content:[
ImageView{image:
Image{url: "http://java.sun.com/docs/books/tutorial/2d/basic2d/examples/images/weather-sun.png"}
}
]
}//Scene
}//Stage


編譯和運行之後,此修改後的代碼將生成以下窗口。

 
具有背景圖像的畫幀
圖 2:使用背景圖像的窗口
 



注意:由於沒有指定窗口的寬度和高度,因此圖像剛好填滿窗口。

通過繪製 5 個首尾相接的弧來創建實際的雲。第一個弧的終點是第二個弧的起點。下圖對此進行了說明。

 
形成雲的弧的端點
圖 3:形成雲的弧的端點
 

 

要在代碼中繪製此雲,您需要執行以下步驟:

  1. 使用 javafx.scene.shape 軟件包中的 MoveToArcToPath 類,如以下代碼片段所示。

    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
     
    MoveTo 類用於指示此形狀的起點,ArcTo 類用於創建弧段。使用 Path 類(表示一個簡單的形狀)將所有弧段組合成一個形狀,然後啓用基本的幾何路徑構造。如果需要創建一個自己的形狀,使其不同於 javafx.scene.shape 軟件包中提供的基本圖形形狀,則 Path 類很有用。Path 類擴展了 Node 類,並繼承了後者的所有實例變量和函數。


    注意:sweepFlag 實例變量已設置爲 true,因此按順時針方向(“正”角度)繪製弧。如果按逆時針方向繪製弧,這些弧將不能正確彎曲。
  2. 應用以下代碼創建照明效果,使雲具有浮雕感。

    effect: Lighting{light: DistantLight{azimuth: 90}}
     
    這種效果模擬使用一個遠距光源照亮對象。azimuth 實例變量用於定義光源的角度。
  3. MoveToArcToPathLightingDistantLight 類添加 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 實例變量不變。請執行以下步驟:

  1. Path 對象的 translateY 變量設置爲 15。
  2. 爲起始點 (0, 15) 和結束點 (387, 15) 定義關鍵幀。要計算這些值,請考慮圖像大小 (470x119) 和形狀大小 (83x64)。下圖說明了這些尺寸。

     
    關鍵幀
    圖 5:關鍵幀
     
     
    動畫沿着由 javafx.animation.Timeline 對象表示的時間線進行。每條時間線包含由 javafx.animation.KeyFrame 對象表示的兩個或多個關鍵幀。
  3. 創建具有兩個關鍵幀的時間線來執行雲的水平運動,並在啓動應用程序時開始此運動。起始點和結束點之間的位置是使用線性插值計算的。

    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 對象週期內設置關聯值。timejavafx.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();
     
  4. Path 對象的 translateX 實例變量綁定到 x 變量,如以下代碼片段所示:

    Path{
    ...
    translateX: bind x
    ...
    }
     
    x 變量發生變化時,Path 對象的 translateX 對象也隨之發生變化。有關數據綁定機制的更多詳細信息,請參見對 UI 對象應用數據綁定

您可以使用 Timeline 類的實例變量來控制時間線週期。

  1. repeatCount 實例變量設置爲 Timeline.INDEFINITE 可以循環動畫。
  2. autoReverse 實例變量設置爲 true 可以啓用雙向運動。

以下代碼可完成這些任務:

import javafx.animation.Timeline;
import javafx.animation.KeyFrame;
import javafx.animation.Interpolator;

var x: Number;

Timeline {
repeatCount: Timeline.INDEFINITE
autoReverse: true
keyFrames: [
at (0s) {x => 0.0},
at (7s) {x => 387.0 tween Interpolator.LINEAR}
]
}.play();


此應用程序修改後的代碼如下所示:

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();

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: 15
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


編譯和運行之後,此代碼將生成以下窗口:

 
水平運動
圖 6:水平運動
 


此動畫應用程序使用可按均勻時間增量移動對象的線性插值。您可以嘗試其他形式的插值。例如,如果您設置 Interpolator.EASEBOTH 類型,則在時間線週期的起點和終點,雲的運動速度將稍微下降。

您可以通過創建最初所需的飄浮效果來改進應用程序。

  1. 爲此形狀的 y 座標創建另一個時間線。
  2. 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 的其他動畫功能。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章