JavaFX 時(shí)間軸動畫

2018-03-20 10:05 更新

JavaFX教程 - JavaFX時(shí)間軸動畫


通過更改節(jié)點(diǎn)的屬性(如大小,位置和顏色等)創(chuàng)建動畫。

時(shí)間軸動畫會隨著時(shí)間的推移更新屬性值。

JavaFX支持關(guān)鍵幀動畫。動畫狀態(tài)場景在某些時(shí)間由開始和結(jié)束關(guān)鍵幀聲明。

什么是關(guān)鍵值?

JavaFX允許我們創(chuàng)建可以內(nèi)插的定時(shí)事件預(yù)定義的值來生成動畫。

例如,為了產(chǎn)生淡出效果,我們將目標(biāo)為節(jié)點(diǎn)的不透明屬性來內(nèi)插其值,從完全不透明的1開始到在一段時(shí)間內(nèi)是透明的0。

以下代碼定義了一個(gè)KeyValue,它以從1開始并以0結(jié)尾的矩形的不透明度屬性為目標(biāo)。

Rectangle rectangle  = new Rectangle(0, 0, 50,   50);
KeyValue keyValue  = new KeyValue(rectangle.opacityProperty(), 0);

KeyValue對象實(shí)際上不內(nèi)插值。它定義屬性的開始和結(jié)束值。

默認(rèn)情況下,KeyValue對象將有一個(gè)線性插值器。

KeyValue可以用不同的方式定義類型的內(nèi)插器,如線性,ease in, 或ease out。

以下代碼定義了一個(gè)鍵值,它將使用Interpolator.EASE_OUT內(nèi)插器從左到右將矩形動畫化100像素。漸弱將減慢結(jié)束鍵值之前的漸變。

Rectangle rectangle  = new Rectangle(0, 0, 50,   50);
KeyValue keyValue  = new KeyValue(rectangle.xProperty(), 100, Interpolator.EASE_OUT);

什么是關(guān)鍵幀?

當(dāng)動畫發(fā)生時(shí),每個(gè)步驟稱為由KeyFrame對象定義的關(guān)鍵幀。

關(guān)鍵幀在javafx.util.Duration中定義的時(shí)間段內(nèi)插入在KeyValue對象中定義的鍵值。

當(dāng)創(chuàng)建KeyFrame對象時(shí),構(gòu)造函數(shù)需要一個(gè)定時(shí)持續(xù)時(shí)間(Duration)。KeyFrame構(gòu)造函數(shù)接受一個(gè)或多個(gè)鍵值。

假設(shè)我們要從左上角到右下角移動一個(gè)矩形,我們定義一個(gè)具有1000毫秒持續(xù)時(shí)間的關(guān)鍵幀和兩個(gè)表示矩形的x和y屬性的關(guān)鍵值。

以下代碼定義關(guān)鍵幀,以一秒或1000毫秒將矩形的左上角(0,0)移動到點(diǎn)(100,100)。

Rectangle rectangle  = new Rectangle(0, 0, 50, 50);

KeyValue xValue  = new KeyValue(rectangle.xProperty(), 100); 
KeyValue yValue  = new KeyValue(rectangle.yProperty(), 100);

KeyFrame keyFrame  = new KeyFrame(Duration.millis(1000), xValue, yValue);

什么是時(shí)間軸?

時(shí)間軸是由許多KeyFrame對象組成的一個(gè)動畫序列。每個(gè)KeyFrame對象按順序運(yùn)行。

時(shí)間軸是javafx.animation.Animation類的子類,它具有標(biāo)準(zhǔn)屬性,如循環(huán)計(jì)數(shù)和自動反轉(zhuǎn)。

循環(huán)計(jì)數(shù)是播放動畫的次數(shù)。要無限期地播放動畫,請使用值Timeline.INDEFINITE。

auto-reverse 屬性是一個(gè)布爾標(biāo)志,表示動畫可以向后播放時(shí)間軸。

默認(rèn)情況下,周期計(jì)數(shù)設(shè)置為1,自動反轉(zhuǎn)設(shè)置為false。

要向時(shí)間軸對象添加關(guān)鍵幀,請使用getKeyFrames().addAll()方法。

以下代碼演示了自動反轉(zhuǎn)設(shè)置為true時(shí)無限期播放的時(shí)間軸。

Timeline timeline  = new Timeline(); 
timeline.setCycleCount(Timeline.INDEFINITE); 
timeline.setAutoReverse(true); 
timeline.getKeyFrames().addAll(keyFrame1,  keyFrame2); 
timeline.play();

例子

/*
 * Copyright (c) 2011, 2012 Oracle and/or its affiliates.
 * All rights reserved. Use is subject to license terms.
 *
 * This file is available and licensed under the following license:
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  - Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  - Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the distribution.
 *  - Neither the name of Oracle nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

//package colorfulcircles;

import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.effect.BlendMode;
import javafx.scene.effect.BoxBlur;
import javafx.scene.paint.Color;
import javafx.scene.paint.CycleMethod;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Stop;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.StrokeType;
import javafx.stage.Stage;
import javafx.util.Duration;
import static java.lang.Math.random;

public class Main extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        Group root = new Group();
        Scene scene = new Scene(root, 800, 600, Color.BLACK);
        primaryStage.setScene(scene);
        Group circles = new Group();
        for (int i = 0; i < 30; i++) {
            Circle circle = new Circle(150, Color.web("white", 0.05));
            circle.setStrokeType(StrokeType.OUTSIDE);
            circle.setStroke(Color.web("white", 0.16));
            circle.setStrokeWidth(4);
            circles.getChildren().add(circle);
        }
        Rectangle colors = new Rectangle(scene.getWidth(), scene.getHeight(),
                new LinearGradient(0f, 1f, 1f, 0f, true, CycleMethod.NO_CYCLE, new Stop[]{
                    new Stop(0, Color.web("#f8bd55")),
                    new Stop(0.14, Color.web("#c0fe56")),
                    new Stop(0.28, Color.web("#5dfbc1")),
                    new Stop(0.43, Color.web("#64c2f8")),
                    new Stop(0.57, Color.web("#be4af7")),
                    new Stop(0.71, Color.web("#ed5fc2")),
                    new Stop(0.85, Color.web("#ef504c")),
                    new Stop(1, Color.web("#f2660f")),}));
        Group blendModeGroup =
                new Group(new Group(new Rectangle(scene.getWidth(), scene.getHeight(),
                Color.BLACK), circles), colors);
        colors.setBlendMode(BlendMode.OVERLAY);
        root.getChildren().add(blendModeGroup);
        circles.setEffect(new BoxBlur(10, 10, 3));
        Timeline timeline = new Timeline();
        for (Node circle : circles.getChildren()) {
            timeline.getKeyFrames().addAll(
                    new KeyFrame(Duration.ZERO, // set start position at 0
                    new KeyValue(circle.translateXProperty(), random() * 800),
                    new KeyValue(circle.translateYProperty(), random() * 600)),
                    new KeyFrame(new Duration(40000), // set end position at 40s
                    new KeyValue(circle.translateXProperty(), random() * 800),
                    new KeyValue(circle.translateYProperty(), random() * 600)));
        }
        // play 40s of animation
        timeline.play();

        primaryStage.show();
    }
}

上面的代碼生成以下結(jié)果。

null

時(shí)間軸事件

/*
 * Copyright (c) 2011, Pro JavaFX Authors
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. Neither the name of JFXtras nor the names of its contributors may be used
 *    to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * Metronome1Main.fx - A simple example of animation using a Timeline
 *
 *  Developed 2011 by James L. Weaver jim.weaver [at] javafxpert.com
 *  as a JavaFX SDK 2.0 example for the Pro JavaFX book.
 */
import javafx.animation.AnimationTimer;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
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.stage.Stage;
import javafx.util.Duration;
 
public class Main 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);
    }
  } 
  

上面的代碼生成以下結(jié)果。

null
以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號