下载APP 编程狮,随时随地学编程
返回 首页

Java 教程

JavaFX 时间轴动画

JavaFX教程 - JavaFX时间轴动画


通过更改节点的属性(如大小,位置和颜色等)创建动画。

时间轴动画会随着时间的推移更新属性值。

JavaFX支持关键帧动画。动画状态场景在某些时间由开始和结束关键帧声明。

什么是关键值?

JavaFX允许我们创建可以内插的定时事件预定义的值来生成动画。

例如,为了产生淡出效果,我们将目标为节点的不透明属性来内插其值,从完全不透明的1开始到在一段时间内是透明的0。

以下代码定义了一个KeyValue,它以从1开始并以0结尾的矩形的不透明度属性为目标。

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

KeyValue对象实际上不内插值。它定义属性的开始和结束值。

默认情况下,KeyValue对象将有一个线性插值器。

KeyValue可以用不同的方式定义类型的内插器,如线性,ease in, 或ease out。

以下代码定义了一个键值,它将使用Interpolator.EASE_OUT内插器从左到右将矩形动画化100像素。渐弱将减慢结束键值之前的渐变。

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

什么是关键帧?

当动画发生时,每个步骤称为由KeyFrame对象定义的关键帧。

关键帧在javafx.util.Duration中定义的时间段内插入在KeyValue对象中定义的键值。

当创建KeyFrame对象时,构造函数需要一个定时持续时间(Duration)。KeyFrame构造函数接受一个或多个键值。

假设我们要从左上角到右下角移动一个矩形,我们定义一个具有1000毫秒持续时间的关键帧和两个表示矩形的x和y属性的关键值。

以下代码定义关键帧,以一秒或1000毫秒将矩形的左上角(0,0)移动到点(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);

什么是时间轴?

时间轴是由许多KeyFrame对象组成的一个动画序列。每个KeyFrame对象按顺序运行。

时间轴是javafx.animation.Animation类的子类,它具有标准属性,如循环计数和自动反转。

循环计数是播放动画的次数。要无限期地播放动画,请使用值Timeline.INDEFINITE。

auto-reverse 属性是一个布尔标志,表示动画可以向后播放时间轴。

默认情况下,周期计数设置为1,自动反转设置为false。

要向时间轴对象添加关键帧,请使用getKeyFrames().addAll()方法。

以下代码演示了自动反转设置为true时无限期播放的时间轴。

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

上面的代码生成以下结果。

null

时间轴事件

/*
 * 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);
    }
  } 
  

上面的代码生成以下结果。

null
目录

JavaFX 形状

JavaFX 线
JavaFX 矩形椭圆
JavaFX 路径
JavaFX 圆弧
JavaFX 多边形折线
JavaFX 曲线
JavaFX 颜色
JavaFX 渐变颜色
JavaFX 文本

JavaFX 属性

JavaFX 属性
JavaFX 绑定
JavaFX 集合

JavaFX UI控件

JavaFX 标签
JavaFX 按钮
JavaFX 单选按钮
JavaFX 切换按钮
JavaFX 复选框
JavaFX 选择框
JavaFX 文本字段
JavaFX 密码字段
JavaFX 超链接
JavaFX 滑块
JavaFX 进度条
JavaFX 进度显示器
JavaFX 滚动条
JavaFX 图像显示
JavaFX 日期选择器
JavaFX 颜色选择器
JavaFX 文件选择器
JavaFX 菜单
JavaFX 工具提示
JavaFX 分隔符
JavaFX 组合框
JavaFX HTMLEditor
JavaFX 分页
JavaFX 列表视图
JavaFX 表视图
JavaFX 树视图
JavaFX 树表视图

JavaFX 图

JavaFX 饼图
JavaFX 折线图
JavaFX 区域图
JavaFX 气泡图
JavaFX 条形图
JavaFX 散点图

JavaFX 效果

JavaFX 效果

Java 动画

JavaFX 过渡
JavaFX 时间轴动画

JavaFX 主题

JavaFX CSS

JavaFX 转换

JavaFX 转换

JavaFX Web

JavaFX WebEngine
JavaFX WebView

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }